/// <summary> /// Registers all the ContractRequirement classes. /// </summary> void RegisterContractRequirements() { LoggingUtil.LogDebug(this, "Start Registering ContractRequirements"); // Register each type foreach (Type subclass in GetAllTypes <ContractRequirement>().Where(t => !t.IsAbstract)) { string name = subclass.Name; if (name.EndsWith("Requirement")) { name = name.Remove(name.Length - 11, 11); } try { ContractRequirement.Register(subclass, name); } catch (Exception e) { LoggingUtil.LogError(this, "Error registering contract requirement " + subclass.Name); LoggingUtil.LogException(e); } } LoggingUtil.LogInfo(this, "Finished Registering ContractRequirements"); }
/// <summary> /// Registers all the BehaviourFactory classes. /// </summary> void RegisterBehaviourFactories() { LoggingUtil.LogDebug(this, "Start Registering BehaviourFactories"); // Register each type with the behaviour factory foreach (Type subclass in GetAllTypes <BehaviourFactory>().Where(t => !t.IsAbstract)) { string name = subclass.Name; if (name.EndsWith("Factory")) { name = name.Remove(name.Length - 7, 7); } try { BehaviourFactory.Register(subclass, name); } catch (Exception e) { LoggingUtil.LogError(this, "Error registering behaviour factory " + subclass.Name); LoggingUtil.LogException(e); } } LoggingUtil.LogInfo(this, "Finished Registering BehaviourFactories"); }
protected override void OnSave(ConfigNode node) { try { node.AddValue("subtype", subType); node.AddValue("title", title); node.AddValue("description", description); node.AddValue("synopsis", synopsis); node.AddValue("completedMessage", completedMessage); node.AddValue("notes", notes); node.AddValue("hash", hash); foreach (ContractBehaviour behaviour in behaviours) { ConfigNode child = new ConfigNode("BEHAVIOUR"); behaviour.Save(child); node.AddNode(child); } } catch (Exception e) { LoggingUtil.LogError(this, "Error saving contract to persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.CONTRACT_SAVE, e, this); SetState(State.Failed); } }
public override void OnLoad(ConfigNode node) { try { foreach (ConfigNode child in node.GetNodes("CONTRACT")) { ConfiguredContract contract = null; try { contract = new ConfiguredContract(); Contract.Load(contract, child); } catch (Exception e) { LoggingUtil.LogWarning(this, "Ignored an exception while trying to load a pre-loaded contract:"); LoggingUtil.LogException(e); } if (contract != null && contract.contractType != null) { contract.preLoaded = true; contracts.Add(contract); } } } catch (Exception e) { LoggingUtil.LogError(this, "Error loading ContractPreLoader from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "ContractPreLoader"); } }
public override void OnSave(ConfigNode node) { try { base.OnSave(node); ConfigNode dataNode = new ConfigNode("DATA"); node.AddNode(dataNode); // Handle individual values foreach (KeyValuePair <string, System.Object> p in data) { StoreToConfigNode(dataNode, p.Key, p.Value); } // Handle config nodes foreach (ConfigNode childNode in configNodes.Values) { dataNode.AddNode(childNode); } } catch (Exception e) { LoggingUtil.LogError(this, "Error saving PersistentDataStore to persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_SAVE, e, "PersistentDataStore"); } }
public override void OnSave(ConfigNode node) { try { foreach (ConfiguredContract contract in contracts.Where(c => c.ContractState == Contract.State.Offered)) { ConfigNode child = new ConfigNode("CONTRACT"); node.AddNode(child); contract.Save(child); } ConfigNode unreadNode = new ConfigNode("UNREAD_CONTRACTS"); node.AddNode(unreadNode); foreach (Contract c in ContractSystem.Instance.Contracts.Where(c => unreadContracts.Contains(c.ContractGuid))) { unreadNode.AddValue("contract", c.ContractGuid); } foreach (ConfiguredContract c in contracts.Where(c => unreadContracts.Contains(c.ContractGuid))) { unreadNode.AddValue("contract", c.ContractGuid); } } catch (Exception e) { LoggingUtil.LogError(this, "Error saving ContractPreLoader to persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_SAVE, e, "ContractPreLoader"); } }
protected override bool Generate() { // Special case for pre-loader if (ContractState == State.Withdrawn) { return(true); } try { if (contractType != null) { return(true); } else { return(false); } } catch (Exception e) { LoggingUtil.LogError(this, "Error generating contract!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.CONTRACT_GENERATION, e, contractType == null ? "unknown" : contractType.FullName); try { GenerateFailed(); } catch { } return(false); } }
public static IEnumerable <Type> GetAllTypes <T>() { // Get everything that extends the given type List <Type> allTypes = new List <Type>(); foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { IEnumerable <Type> types = null; try { types = from type in assembly.GetTypes() where (type.IsSubclassOf(typeof(T)) || type.GetInterface(typeof(T).Name) != null) select type; } catch (Exception e) { LoggingUtil.LogException(new Exception("Error loading types from assembly " + assembly.FullName, e)); continue; } foreach (Type t in types) { Type foundType = t; if (foundType != null) { yield return(foundType); } } } }
public override void OnLoad(ConfigNode node) { try { lastMCButton = ConfigNodeUtil.ParseValue <MissionControlButton>(node, "lastMCButton", MissionControlButton.All); DisplayOfferedOrbits = ConfigNodeUtil.ParseValue <bool?>(node, "DisplayOfferedOrbits", (bool?)ContractDefs.DisplayOfferedOrbits).Value; DisplayOfferedWaypoints = ConfigNodeUtil.ParseValue <bool?>(node, "DisplayOfferedWaypoints", (bool?)ContractDefs.DisplayOfferedWaypoints).Value; DisplayActiveOrbits = ConfigNodeUtil.ParseValue <bool?>(node, "DisplayActiveOrbits", (bool?)true).Value; DisplayActiveWaypoints = ConfigNodeUtil.ParseValue <bool?>(node, "DisplayActiveWaypoints", (bool?)true).Value; foreach (ConfigNode groupNode in node.GetNodes("CONTRACT_GROUP")) { string groupName = groupNode.GetValue("group"); if (ContractGroup.contractGroups.ContainsKey(groupName)) { ContractGroup group = ContractGroup.contractGroups[groupName]; ContractGroupDetails details = new ContractGroupDetails(group); details.enabled = ConfigNodeUtil.ParseValue <bool>(groupNode, "enabled"); contractGroupDetails[group.name] = details; } else { LoggingUtil.LogWarning(this, "Couldn't find contract group with name '" + groupName + "'"); } } foreach (ConfigNode stateNode in node.GetNodes("CONTRACT_STATE")) { string typeName = stateNode.GetValue("type"); if (!string.IsNullOrEmpty(typeName)) { Type contractType = null; try { contractType = ConfigNodeUtil.ParseTypeValue(typeName); StockContractDetails details = new StockContractDetails(contractType); details.enabled = ConfigNodeUtil.ParseValue <bool>(stateNode, "enabled"); stockContractDetails[contractType] = details; ContractDisabler.SetContractState(contractType, details.enabled); } catch (ArgumentException) { LoggingUtil.LogWarning(this, "Couldn't find contract type with name '" + typeName + "'"); } } } } catch (Exception e) { LoggingUtil.LogError(this, "Error loading ContractConfiguratorSettings from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "ContractConfiguratorSettings"); } }
/// <summary> /// Loads all the contact configuration group nodes. /// </summary> private IEnumerator <YieldInstruction> LoadGroupConfig() { // Load all the contract groups LoggingUtil.LogDebug(this, "Loading CONTRACT_GROUP nodes."); ConfigNode[] contractGroups = GameDatabase.Instance.GetConfigNodes("CONTRACT_GROUP"); foreach (ConfigNode groupConfig in contractGroups) { // Create the group string name = groupConfig.GetValue("name"); LoggingUtil.LogInfo(this, "Loading CONTRACT_GROUP: '" + name + "'"); ContractGroup contractGroup = null; try { contractGroup = new ContractGroup(name); } catch (ArgumentException) { LoggingUtil.LogError(this, "Couldn't load CONTRACT_GROUP '" + name + "' due to a duplicate name."); } // Peform the actual load if (contractGroup != null) { bool success = false; try { ConfigNodeUtil.ClearCache(true); success = contractGroup.Load(groupConfig); } catch (Exception e) { Exception wrapper = new Exception("Error loading CONTRACT_GROUP '" + name + "'", e); LoggingUtil.LogException(wrapper); } finally { if (!success) { ContractGroup.contractGroups.Remove(name); } } } } if (!reloading) { yield return(new WaitForEndOfFrame()); } // Emit settings for the menu SettingsBuilder.EmitSettings(); yield break; }
public override void OnLoad(ConfigNode node) { try { base.OnLoad(node); ConfigNode dataNode = node.GetNode("DATA"); if (dataNode != null) { // Handle individual values foreach (ConfigNode.Value pair in dataNode.values) { string typeName = pair.value.Remove(pair.value.IndexOf(":")); string value = pair.value.Substring(typeName.Length + 1); Type type = ConfigNodeUtil.ParseTypeValue(typeName); if (type == typeof(string)) { data[pair.name] = value; } else if (type.Name == "List`1") { BaseParser parser = BaseParser.NewParser(type); if (parser == null) { throw new Exception("Couldn't read list of values of type '" + type.GetGenericArguments().First().Name + "'."); } data[pair.name] = parser.ParseExpressionGeneric("", value, null); } else { // Get the ParseValue method MethodInfo parseValueMethod = typeof(ConfigNodeUtil).GetMethods().Where(m => m.Name == "ParseSingleValue").Single(); parseValueMethod = parseValueMethod.MakeGenericMethod(new Type[] { type }); // Invoke the ParseValue method data[pair.name] = parseValueMethod.Invoke(null, new object[] { pair.name, value, false }); } } // Handle config nodes foreach (ConfigNode childNode in dataNode.GetNodes()) { configNodes[childNode.name] = childNode; } } } catch (Exception e) { LoggingUtil.LogError(this, "Error loading PersistentDataStore from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "PersistentDataStore"); } }
public override void OnLoad(ConfigNode node) { try { Load(); } catch (Exception e) { LoggingUtil.LogError(this, "Error loading BiomeTracker data from custom file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "BiomeTracker"); } }
/// <summary> /// Validates the given SCANname and sees if SCANsat has a SCANtype that matches it. /// </summary> /// <param name="SCANname">The SCANname to validate.</param> /// <returns>Whether the validation succeeded, outputs an error if it did not.</returns> public static bool ValidateSCANname(string SCANname) { try { GetSCANtype(SCANname); } catch (Exception e) { LoggingUtil.LogException(e); return(false); } return(true); }
public override void OnSave(ConfigNode node) { try { base.OnSave(node); foreach (KeyValuePair <string, VesselInfo> p in vessels) { VesselInfo vi = p.Value; // First find the vessel by id Vessel vessel = FlightGlobals.Vessels.Find(v => v != null && v.id == vi.id); if (HighLogic.LoadedScene == GameScenes.FLIGHT) { // If not found, attempt to find it by hash if (vessel == null) { vessel = FlightGlobals.Vessels.Find(v => v != null && v.GetHashes().Contains(vi.hash)); } // If found, verify the hash else { IEnumerable <uint> hashes = vessel.GetHashes(); if (hashes.Any() && !hashes.Contains(vi.hash)) { LoggingUtil.LogVerbose(this, "Setting hash for " + vi.id + " on save from " + vi.hash + " to " + hashes.FirstOrDefault()); vi.hash = hashes.FirstOrDefault(); } } } if (vessel != null) { ConfigNode child = new ConfigNode("VESSEL"); child.AddValue("key", p.Key); child.AddValue("id", vi.id); child.AddValue("hash", vi.hash); node.AddNode(child); } } } catch (Exception e) { LoggingUtil.LogError(this, "Error saving ContractVesselTracker to persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_SAVE, e, "ContractVesselTracker"); } }
protected override void OnLoad(ConfigNode node) { try { subType = node.GetValue("subtype"); contractType = string.IsNullOrEmpty(subType) ? null : ContractType.GetContractType(subType); title = ConfigNodeUtil.ParseValue <string>(node, "title", contractType != null ? contractType.title : subType); description = ConfigNodeUtil.ParseValue <string>(node, "description", contractType != null ? contractType.description : ""); synopsis = ConfigNodeUtil.ParseValue <string>(node, "synopsis", contractType != null ? contractType.synopsis : ""); completedMessage = ConfigNodeUtil.ParseValue <string>(node, "completedMessage", contractType != null ? contractType.completedMessage : ""); notes = ConfigNodeUtil.ParseValue <string>(node, "notes", contractType != null ? contractType.notes : ""); hash = ConfigNodeUtil.ParseValue <int>(node, "hash", contractType != null ? contractType.hash : 0); foreach (ConfigNode child in node.GetNodes("BEHAVIOUR")) { ContractBehaviour behaviour = ContractBehaviour.LoadBehaviour(child, this); behaviours.Add(behaviour); } // If the contract type is null, then it likely means that it was uninstalled if (contractType == null) { LoggingUtil.LogWarning(this, "Error loading contract for contract type '" + subType + "'. The contract type either failed to load or was uninstalled."); try { SetState(State.Failed); } catch { } return; } } catch (Exception e) { LoggingUtil.LogError(this, "Error loading contract from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.CONTRACT_LOAD, e, this); try { SetState(State.Failed); } catch { } } }
public override void OnSave(ConfigNode node) { try { base.OnSave(node); foreach (ScienceSubject s in trackedSubjects) { node.AddValue("subject", s.id); } } catch (Exception e) { LoggingUtil.LogError(this, "Error saving ScienceReporter to persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_SAVE, e, "ScienceReporter"); } }
public override void OnSave(ConfigNode node) { try { foreach (ConfiguredContract contract in contracts.Where(c => c.ContractState == Contract.State.Offered)) { ConfigNode child = new ConfigNode("CONTRACT"); node.AddNode(child); contract.Save(child); } } catch (Exception e) { LoggingUtil.LogError(this, "Error saving ContractPreLoader to persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_SAVE, e, "ContractPreLoader"); } }
/// <summary> /// Checks if all the given ContractRequirement meet the requirement. /// </summary> /// <param name="contract">Contract to check</param> /// <param name="contractType">Contract type of the contract (in case the contract type has not yet been assigned).</param> /// <param name="contractRequirements">The list of requirements to check</param> /// <returns>Whether the requirement is met or not.</returns> public static bool RequirementsMet(ConfiguredContract contract, ContractType contractType, IEnumerable <ContractRequirement> contractRequirements) { bool allReqMet = true; try { LoggingUtil.LogVerbose(typeof(ContractRequirement), "Checking requirements for contract '{0}'", contractType.name); foreach (ContractRequirement requirement in contractRequirements) { if (requirement.enabled) { if (requirement.checkOnActiveContract || contract == null || contract.ContractState != Contract.State.Active) { allReqMet = allReqMet && requirement.CheckRequirement(contract); if (!allReqMet) { LoggingUtil.Log(contract != null && contract.ContractState == Contract.State.Active ? LoggingUtil.LogLevel.INFO : contract != null && contract.ContractState == Contract.State.Offered ? LoggingUtil.LogLevel.DEBUG : LoggingUtil.LogLevel.VERBOSE, requirement.GetType(), "Contract {0}: requirement {1} was not met.", contractType.name, requirement.name); break; } } } } // Force fail the contract if a requirement becomes unmet if (contract != null && contract.ContractState == Contract.State.Active && !allReqMet) { // Fail the contract - unfortunately, the player won't know why. :( contract.Fail(); // Force the stock contracts window to refresh GameEvents.Contract.onContractsLoaded.Fire(); } } catch (Exception e) { LoggingUtil.LogException(new Exception("ContractConfigurator: Exception checking requirements!", e)); return(false); } return(allReqMet); }
public override bool LoadFromConfig(ConfigNode configNode) { // Before loading, verify the SCANsat version if (!SCANsatUtil.VerifySCANsatVersion()) { return(false); } // Load base class bool valid = base.LoadFromConfig(configNode); // Do not check the requirement on active contracts. Otherwise when they scan the // contract is invalidated, which is usually not what's meant. checkOnActiveContract = false; valid &= ConfigNodeUtil.ParseValue <string>(configNode, "scanType", x => scanType = x, this, "Anomaly", SCANsatUtil.ValidateSCANname); valid &= ConfigNodeUtil.ParseValue <double>(configNode, "latitude", x => latitude = x, this, 0.0); valid &= ConfigNodeUtil.ParseValue <double>(configNode, "longitude", x => longitude = x, this, 0.0); valid &= ConfigNodeUtil.MutuallyExclusive(configNode, new string[] { "latitude", "longitude" }, new string[] { "pqsCity" }, this); valid &= ValidateTargetBody(configNode); string pqsName = null; valid &= ConfigNodeUtil.ParseValue <string>(configNode, "pqsCity", x => pqsName = x, this, (string)null); if (pqsName != null) { try { pqsCity = targetBody.GetComponentsInChildren <PQSCity>(true).Where(pqs => pqs.name == pqsName).First(); } catch (Exception e) { LoggingUtil.LogError(this, "Couldn't load PQSCity with name '" + pqsCity + "'"); LoggingUtil.LogException(e); valid = false; } } return(valid); }
public override void OnLoad(ConfigNode node) { try { base.OnLoad(node); ConfigNode dataNode = node.GetNode("DATA"); if (dataNode != null) { // Handle individual values foreach (ConfigNode.Value pair in dataNode.values) { string typeName = pair.value.Remove(pair.value.IndexOf(":")); string value = pair.value.Substring(typeName.Length + 1, pair.value.Length - typeName.Length - 1); Type type = Type.GetType(typeName); if (type == typeof(string)) { data[pair.name] = pair.value; } else { data[pair.name] = type.InvokeMember("Parse", System.Reflection.BindingFlags.InvokeMethod, null, null, new string[] { value }); } } // Handle config nodes foreach (ConfigNode childNode in dataNode.GetNodes()) { configNodes[childNode.name] = childNode; } } } catch (Exception e) { LoggingUtil.LogError(this, "Error loading PersistentDataStore from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "PersistentDataStore"); } }
public override void OnLoad(ConfigNode node) { try { base.OnLoad(node); foreach (string id in node.GetValuesList("subject")) { ScienceSubject s = ResearchAndDevelopment.GetSubjectByID(id); if (s != null) { trackedSubjects.Add(s); } } } catch (Exception e) { LoggingUtil.LogError(this, "Error loading ScienceReporter from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "ScienceReporter"); } }
public override void OnLoad(ConfigNode node) { try { base.OnLoad(node); foreach (ConfigNode child in node.GetNodes("VESSEL")) { string key = child.GetValue("key"); Guid id = new Guid(child.GetValue("id")); uint hash = ConfigNodeUtil.ParseValue <uint>(child, "hash", 0); StartCoroutine(CompleteVesselLoad(key, id)); vessels[key] = new VesselInfo(id, hash); } } catch (Exception e) { LoggingUtil.LogError(this, "Error loading ContractVesselTracker from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "ContractVesselTracker"); } }
public override void OnLoad(ConfigNode node) { try { base.OnLoad(node); foreach (ConfigNode child in node.GetNodes("VESSEL")) { string key = child.GetValue("key"); Guid id = new Guid(child.GetValue("id")); uint hash = ConfigNodeUtil.ParseValue <uint>(child, "hash", 0); Vessel vessel = FlightGlobals.Vessels.Find(v => v != null && v.id == id); if (vessel == null || vessel.state == Vessel.State.DEAD) { id = Guid.Empty; } else if (hash == 0 && HighLogic.LoadedScene == GameScenes.FLIGHT) { hash = vessel.GetHashes().FirstOrDefault(); LoggingUtil.LogVerbose(this, "Setting hash for " + id + " on load to: " + hash); } if (id != Guid.Empty) { vessels[key] = new VesselInfo(id, hash); } } } catch (Exception e) { LoggingUtil.LogError(this, "Error loading ContractVesselTracker from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "ContractVesselTracker"); } }
public override void OnSave(ConfigNode node) { try { node.AddValue("lastMCButton", lastMCButton); node.AddValue("DisplayOfferedOrbits", DisplayOfferedOrbits); node.AddValue("DisplayOfferedWaypoints", DisplayOfferedWaypoints); node.AddValue("DisplayActiveOrbits", DisplayActiveOrbits); node.AddValue("DisplayActiveWaypoints", DisplayActiveWaypoints); foreach (ContractGroupDetails details in contractGroupDetails.Values.Where(d => d.group != null)) { ConfigNode groupNode = new ConfigNode("CONTRACT_GROUP"); node.AddNode(groupNode); groupNode.AddValue("group", details.group.name); groupNode.AddValue("enabled", details.enabled); } foreach (StockContractDetails details in stockContractDetails.Values.Where(d => d.contractType != null)) { ConfigNode stateNode = new ConfigNode("CONTRACT_STATE"); node.AddNode(stateNode); stateNode.AddValue("type", details.contractType.Name); stateNode.AddValue("enabled", details.enabled); } } catch (Exception e) { LoggingUtil.LogError(this, "Error saving ContractConfiguratorSettings to persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_SAVE, e, "ContractConfiguratorSettings"); } }
/// <summary> /// Attempts to parse a value from the config node. Returns a default value if not found. /// Validates return values using the given function. /// </summary> /// <typeparam name="T">The type of value to convert to.</typeparam> /// <param name="configNode">The ConfigNode to read from.</param> /// <param name="key">The key to examine.</param> /// <param name="setter">Function used to set the output value</param> /// <param name="obj">Factory object for error messages.</param> /// <param name="defaultValue">Default value to use if there is no key in the config node</param> /// <param name="validation">Validation function to run against the returned value</param> /// <returns>The parsed value (or default value if not found)</returns> public static bool ParseValue <T>(ConfigNode configNode, string key, Action <T> setter, IContractConfiguratorFactory obj, T defaultValue, Func <T, bool> validation) { // Initialize the data type of the expression if (currentDataNode != null && !currentDataNode.IsInitialized(key)) { currentDataNode.BlankInit(key, typeof(T)); } bool valid = true; T value = defaultValue; if (configNode.HasValue(key) || configNode.HasNode(key)) { try { // Check whether there's a value if (configNode.HasValue(key) && string.IsNullOrEmpty(configNode.GetValue(key))) { LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Required value '" + key + "' is empty."); valid = false; } else { // Load value value = ParseValue <T>(configNode, key, true); } // If value was non-null, run validation if (value != null && (typeof(T) != typeof(string) || ((string)(object)value) != "")) { try { valid = validation.Invoke(value); if (!valid) { // In general, the validation function should throw an exception and give a much better message LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": A validation error occured while loading the key '" + key + "' with value '" + value + "'."); } } catch (Exception e) { if (e is DataNode.ValueNotInitialized) { throw; } LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": A validation error occured while loading the key '" + key + "' with value '" + value + "'."); LoggingUtil.LogException(e); valid = false; } } } catch (Exception e) { if (e.GetType() == typeof(DataNode.ValueNotInitialized)) { string dependency = ((DataNode.ValueNotInitialized)e).key; string path = currentDataNode.Path() + key; LoggingUtil.LogVerbose(typeof(ConfigNodeUtil), "Trying to load " + path + ", but " + dependency + " is uninitialized."); // Defer loading this value DeferredLoadObject <T> loadObj = null; if (!deferredLoads.ContainsKey(path) || deferredLoads[path].GetType().GetGenericArguments().First() != typeof(T)) { deferredLoads[path] = new DeferredLoadObject <T>(configNode, key, setter, obj, validation, currentDataNode); } loadObj = (DeferredLoadObject <T>)deferredLoads[path]; // New dependency - try again if (!loadObj.dependencies.Contains(dependency)) { LoggingUtil.LogVerbose(typeof(ConfigNodeUtil), " New dependency, will re-attempt to load later."); loadObj.dependencies.Add(dependency); return(true); } } LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Error parsing " + key); // Return immediately on deferred load error if (e.GetType() == typeof(DataNode.ValueNotInitialized)) { DataNode.ValueNotInitialized vni = e as DataNode.ValueNotInitialized; LoggingUtil.LogException(new Exception("Unknown identifier '@" + vni.key + "'.")); return(false); } LoggingUtil.LogException(e); valid = false; } finally { AddFoundKey(configNode, key); } } // Store the value if (currentDataNode != null) { currentDataNode[key] = value; if (!currentDataNode.IsDeterministic(key) && initialLoad) { currentDataNode.DeferredLoads.Add(new DeferredLoadObject <T>(configNode, key, setter, obj, validation, currentDataNode)); } } // Invoke the setter function if (valid) { setter.Invoke(value); } return(valid); }
/// <summary> /// Parses a value from a config node. /// </summary> /// <typeparam name="T">The type to convert to.</typeparam> /// <param name="configNode">The ConfigNode to read from</param> /// <param name="key">The key to examine.</param> /// <param name="allowExpression">Whether the read value can be an expression.</param> /// <returns>The parsed value</returns> public static T ParseValue <T>(ConfigNode configNode, string key, bool allowExpression = false) { // Check for required value if (!configNode.HasValue(key)) { if (configNode.HasNode(key)) { return(ParseNode <T>(configNode, key, allowExpression)); } else { throw new ArgumentException("Missing required value '" + key + "'."); } } // Special cases if (typeof(T).Name == "List`1") { int count = configNode.GetValues(key).Count(); // Special handling to try and load the list all at once if (count == 1 && allowExpression) { try { return(ParseSingleValue <T>(key, configNode.GetValue(key), allowExpression)); } catch (Exception e) { Exception handled = e; while (handled != null && handled.GetType() == typeof(Exception)) { handled = handled.InnerException; } // Exceptions we explicitly ignore if (handled == null || handled.GetType() != typeof(DataStoreCastException) && handled.GetType() != typeof(NotSupportedException) && handled.GetType() != typeof(ArgumentNullException) && handled.GetType() != typeof(InvalidCastException)) { // Exceptions we explicitly rethrow if (handled != null && handled.GetType() == typeof(DataNode.ValueNotInitialized)) { throw; } // The rest gets logged LoggingUtil.LogWarning(typeof(ConfigNodeUtil), "Got an unexpected exception trying to load '" + key + "' as a list:"); LoggingUtil.LogException(e); } // And continue on to load the standard way } } // Create the list instance T list = (T)Activator.CreateInstance(typeof(T)); // Create the generic methods MethodInfo parseValueMethod = methodParseSingleValue.MakeGenericMethod(typeof(T).GetGenericArguments()); MethodInfo addMethod = typeof(T).GetMethod("Add"); // Populate the list for (int i = 0; i < count; i++) { string strVal = configNode.GetValue(key, i); try { addMethod.Invoke(list, new object[] { parseValueMethod.Invoke(null, new object[] { key, strVal, allowExpression }) }); } catch (TargetInvocationException tie) { Exception e = ExceptionUtil.UnwrapTargetInvokationException(tie); if (e != null) { throw e; } throw; } } return(list); } else if (typeof(T).Name == "Nullable`1") { // Create the generic method MethodInfo parseValueMethod = typeof(ConfigNodeUtil).GetMethod("ParseValue", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(ConfigNode), typeof(string), typeof(bool) }, null); parseValueMethod = parseValueMethod.MakeGenericMethod(typeof(T).GetGenericArguments()); // Call it try { return((T)parseValueMethod.Invoke(null, new object[] { configNode, key, allowExpression })); } catch (TargetInvocationException tie) { Exception e = ExceptionUtil.UnwrapTargetInvokationException(tie); if (e != null) { throw e; } throw; } } // Get string value, pass to parse single value function string stringValue = configNode.GetValue(key); return(ParseSingleValue <T>(key, stringValue, allowExpression)); }
public bool Initialize(ContractType contractType) { LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel; try { this.contractType = contractType; if (contractType.trace) { LoggingUtil.logLevel = LoggingUtil.LogLevel.VERBOSE; } LoggingUtil.LogDebug(this, "Initializing contract: " + contractType); // Set stuff from contract type subType = contractType.name; hash = contractType.hash; AutoAccept = contractType.autoAccept; // Set the contract expiry if (contractType.maxExpiry == 0.0f) { LoggingUtil.LogDebug(this, contractType.name + ": Setting expirty to none"); SetExpiry(); expiryType = DeadlineType.None; } else { SetExpiry(contractType.minExpiry, contractType.maxExpiry); // Force set the expiry, in stock this is normally done on Contract.Offer() dateExpire = GameTime + TimeExpiry; } // Set the contract deadline if (contractType.deadline == 0.0f) { deadlineType = Contract.DeadlineType.None; } else { SetDeadlineDays(contractType.deadline, null); } // Set rewards SetScience(contractType.rewardScience, contractType.targetBody); SetReputation(contractType.rewardReputation, contractType.failureReputation, contractType.targetBody); SetFunds(contractType.advanceFunds, contractType.rewardFunds, contractType.advanceFunds + contractType.failureFunds, contractType.targetBody); // Copy text from contract type title = contractType.title; synopsis = contractType.synopsis; completedMessage = contractType.completedMessage; notes = contractType.notes; // Set the agent if (contractType.agent != null) { agent = contractType.agent; } else { agent = AgentList.Instance.GetSuitableAgentForContract(this); } // Set description if (string.IsNullOrEmpty(contractType.description) && agent != null) { // Generate the contract description description = TextGen.GenerateBackStories("ConfiguredContract", agent.Name, contractType.topic, contractType.subject, random.Next(), true, true, true); } else { description = contractType.description; } // Generate behaviours behaviours = new List <ContractBehaviour>(); if (!contractType.GenerateBehaviours(this)) { return(false); } // Generate parameters bool paramsGenerated = contractType.GenerateParameters(this); bodiesLoaded = false; contractType.contractBodies = ContractBodies; if (!paramsGenerated) { return(false); } // Do a very late research bodies check try { contractType.ResearchBodiesCheck(this); } catch (ContractRequirementException) { return(false); } // Copy in the requirement nodes requirements = new List <ContractRequirement>(); foreach (ContractRequirement requirement in contractType.Requirements) { requirements.Add(requirement); } LoggingUtil.LogDebug(this, "Initialized contract: " + contractType); return(true); } catch (Exception e) { LoggingUtil.LogError(this, "Error initializing contract " + contractType); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.CONTRACT_GENERATION, e, contractType == null ? "unknown" : contractType.FullName); return(false); } finally { LoggingUtil.logLevel = origLogLevel; } }
protected override void OnLoad(ConfigNode node) { try { subType = node.GetValue("subtype"); contractType = ContractType.GetContractType(subType); title = ConfigNodeUtil.ParseValue <string>(node, "title", contractType != null ? contractType.title : subType); description = ConfigNodeUtil.ParseValue <string>(node, "description", contractType != null ? contractType.description : ""); synopsis = ConfigNodeUtil.ParseValue <string>(node, "synopsis", contractType != null ? contractType.synopsis : ""); completedMessage = ConfigNodeUtil.ParseValue <string>(node, "completedMessage", contractType != null ? contractType.completedMessage : ""); notes = ConfigNodeUtil.ParseValue <string>(node, "notes", contractType != null ? contractType.notes : ""); hash = ConfigNodeUtil.ParseValue <int>(node, "hash", contractType != null ? contractType.hash : 0); targetBody = ConfigNodeUtil.ParseValue <CelestialBody>(node, "targetBody", null); // Load the unique data ConfigNode dataNode = node.GetNode("UNIQUE_DATA"); if (dataNode != null) { // Handle individual values foreach (ConfigNode.Value pair in dataNode.values) { string typeName = pair.value.Remove(pair.value.IndexOf(":")); string value = pair.value.Substring(typeName.Length + 1); Type type = ConfigNodeUtil.ParseTypeValue(typeName); // Prevents issues with vessels not getting loaded in some scenes (ie. VAB) if (type == typeof(Vessel)) { type = typeof(Guid); } if (type == typeof(string)) { uniqueData[pair.name] = value; } else { // Get the ParseValue method MethodInfo parseValueMethod = typeof(ConfigNodeUtil).GetMethods().Where(m => m.Name == "ParseSingleValue").Single(); parseValueMethod = parseValueMethod.MakeGenericMethod(new Type[] { type }); // Invoke the ParseValue method uniqueData[pair.name] = parseValueMethod.Invoke(null, new object[] { pair.name, value, false }); } } } foreach (ConfigNode child in node.GetNodes("BEHAVIOUR")) { ContractBehaviour behaviour = ContractBehaviour.LoadBehaviour(child, this); behaviours.Add(behaviour); } foreach (ConfigNode child in node.GetNodes("REQUIREMENT")) { ContractRequirement requirement = ContractRequirement.LoadRequirement(child); requirements.Add(requirement); } // If the contract type is null, then it likely means that it was uninstalled if (contractType == null) { LoggingUtil.LogWarning(this, "Error loading contract for contract type '" + subType + "'. The contract type either failed to load or was uninstalled."); try { if (ContractState == State.Active || ContractState == State.Offered) { SetState(ContractState == State.Active ? State.Failed : State.Withdrawn); } } catch { } return; } OnContractLoaded.Fire(this); } catch (Exception e) { LoggingUtil.LogError(this, "Error loading contract from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.CONTRACT_LOAD, e, this); try { SetState(State.Failed); } catch { } } }
protected override void OnSave(ConfigNode node) { try { node.SetValue("type", "ConfiguredContract"); node.AddValue("subtype", subType); if (!string.IsNullOrEmpty(title)) { node.AddValue("title", title.Replace("\n", "&br;")); } if (!string.IsNullOrEmpty(description)) { node.AddValue("description", description.Replace("\n", "&br;")); } if (!string.IsNullOrEmpty(synopsis)) { node.AddValue("synopsis", synopsis.Replace("\n", "&br;")); } if (!string.IsNullOrEmpty(completedMessage)) { node.AddValue("completedMessage", completedMessage.Replace("\n", "&br;")); } if (!string.IsNullOrEmpty(notes)) { node.AddValue("notes", notes.Replace("\n", "&br;")); } node.AddValue("hash", hash); if (targetBody != null) { node.AddValue("targetBody", targetBody.name); } // Store the unique data if (uniqueData.Any()) { ConfigNode dataNode = new ConfigNode("UNIQUE_DATA"); node.AddNode(dataNode); foreach (KeyValuePair <string, object> p in uniqueData.Where(p => p.Value != null)) { PersistentDataStore.StoreToConfigNode(dataNode, p.Key, p.Value); } } foreach (ContractBehaviour behaviour in behaviours) { ConfigNode child = new ConfigNode("BEHAVIOUR"); behaviour.Save(child); node.AddNode(child); } // Store requirements if (requirements == null) { requirements = new List <ContractRequirement>(); if (contractType != null) { foreach (ContractRequirement requirement in contractType.Requirements) { requirements.Add(requirement); } } } foreach (ContractRequirement requirement in requirements) { ConfigNode child = new ConfigNode("REQUIREMENT"); if (child.nodes.Count > 0) { requirement.Save(child); node.AddNode(child); } } } catch (Exception e) { LoggingUtil.LogError(this, "Error saving contract '" + subType + "' to persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.CONTRACT_SAVE, e, this); SetState(State.Failed); } }
/// <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); LoggingUtil.LogInfo(this, "Loading CONTRACT_TYPE: '" + name + "'"); // Clear the config node cache ConfigNodeUtil.ClearCache(true); // 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, "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); if (configNode.HasValue("motivation)")) { string motivation; valid &= ConfigNodeUtil.ParseValue <string>(configNode, "motivation", x => motivation = x, this, ""); LoggingUtil.LogWarning(this, "The 'motivation' attribute is no longer supported as of Contract Configurator 1.23.0"); } // Load optional attributes valid &= ConfigNodeUtil.ParseValue <Agent>(configNode, "agent", x => agent = x, this, group != null ? group.agent : null); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "minExpiry", x => minExpiry = x, this, 5.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "maxExpiry", x => maxExpiry = x, this, 100.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, (maxCompletions == 0 ? 4 : 0), x => Validation.GE(x, 0)); // Load rewards valid &= ConfigNodeUtil.ParseValue <float>(configNode, "rewardFunds", x => rewardFunds = x, this, 0.0f); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "rewardReputation", x => rewardReputation = x, this, 0.0f); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "rewardScience", x => rewardScience = x, this, 0.0f); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "failureFunds", x => failureFunds = x, this, 0.0f); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "failureReputation", x => failureReputation = x, this, 0.0f); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "advanceFunds", x => advanceFunds = x, this, 0.0f); // Load other values if (configNode.HasValue("weight")) { double weight; valid &= ConfigNodeUtil.ParseValue <double>(configNode, "weight", x => weight = x, this); LoggingUtil.LogWarning(this, ErrorPrefix() + ": The weight attribute is deprecated as of Contract Configurator 1.15.0. Contracts are no longer generated using a weighted system."); } // 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, DataValueInfo> pair in currentGroup.dataValues) { dataValues[currentGroup.name + ":" + pair.Key] = pair.Value; } // Merge uniquenessChecks foreach (KeyValuePair <string, DataNode.UniquenessCheck> pair in currentGroup.uniquenessChecks) { uniquenessChecks[currentGroup.name + ":" + pair.Key] = pair.Value; } } // Load DATA nodes valid &= dataNode.ParseDataNodes(configNode, this, dataValues, uniquenessChecks); 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, ErrorPrefix() + ": Need at least one parameter for a contract!"); valid = false; } ConfigNodeUtil.SetCurrentDataNode(dataNode); // // Process the DATA_EXPAND nodes - this could cause a restart to the load process // ConfigNode dataExpandNode = configNode.GetNodes("DATA_EXPAND").FirstOrDefault(); if (dataExpandNode != null) { Type type = null; valid &= ConfigNodeUtil.ParseValue <Type>(dataExpandNode, "type", x => type = x, this); if (type != null) { foreach (ConfigNode.Value pair in dataExpandNode.values) { string key = pair.name; if (key != "type") { object value = null; // Create the setter function Type actionType = typeof(Action <>).MakeGenericType(type); Delegate del = Delegate.CreateDelegate(actionType, value, typeof(DataNode).GetMethod("NullAction")); // Set the ParseDataExpandString method generic value MethodInfo method = methodParseExpand.MakeGenericMethod(new Type[] { type }); // Invoke the ParseDataExpandString method List <string> values = (List <string>)method.Invoke(this, new object[] { dataExpandNode, key }); // Stop at this point if we're invalid if (values == null || !valid) { if (values == null) { LoggingUtil.LogWarning(this, ErrorPrefix() + ": Received an empty list of values when trying to do a DATA_EXPAND"); } valid = false; break; } // Expand configNode.RemoveNode(dataExpandNode); foreach (string val in values) { // Set up for expansion ConfigNode copy = configNode.CreateCopy(); string newName = name + "." + val; copy.SetValue("name", newName); // Set up the data node in the copy ConfigNode dataNode = new ConfigNode("DATA"); copy.AddNode(dataNode); dataNode.AddValue("type", dataExpandNode.GetValue("type")); dataNode.AddValue(key, val); ContractType contractTypeCopy = new ContractType(newName); contractTypeCopy.Load(copy); } // Remove the original contractTypes.Remove(name); // Don't do any more loading for this one LoggingUtil.LogInfo(this, "Successfully expanded CONTRACT_TYPE '" + name + "'"); return(valid); } } } } // // Do the deferred loads // valid &= ConfigNodeUtil.ExecuteDeferredLoads(); // // Do generic fields that need to happen after deferred loads // ConfigNodeUtil.SetCurrentDataNode(dataNode); // Generic title valid &= ConfigNodeUtil.ParseValue <string>(configNode, "genericTitle", x => genericTitle = x, this, title); if (!configNode.HasValue("genericTitle") && !dataNode.IsDeterministic("title")) { LoggingUtil.Log(minVersion >= ContractConfigurator.ENHANCED_UI_VERSION ? LoggingUtil.LogLevel.ERROR : LoggingUtil.LogLevel.WARNING, this, ErrorPrefix() + ": The field 'genericTitle' is required when the title is not determistic (ie. when expressions are used)."); // Error on newer versions of contract packs if (minVersion >= ContractConfigurator.ENHANCED_UI_VERSION) { valid = false; } } else if (!dataNode.IsDeterministic("genericTitle")) { valid = false; LoggingUtil.LogError(this, ErrorPrefix() + ": The field 'genericTitle' must be deterministic."); } // Generic description valid &= ConfigNodeUtil.ParseValue <string>(configNode, "genericDescription", x => genericDescription = x, this, description); if (!configNode.HasValue("genericDescription") && !dataNode.IsDeterministic("description")) { LoggingUtil.Log(minVersion >= ContractConfigurator.ENHANCED_UI_VERSION ? LoggingUtil.LogLevel.ERROR : LoggingUtil.LogLevel.WARNING, this, ErrorPrefix() + ": The field 'genericDescription' is required when the description is not determistic (ie. when expressions are used)."); // Error on newer versions of contract packs if (minVersion >= ContractConfigurator.ENHANCED_UI_VERSION) { valid = false; } } else if (!dataNode.IsDeterministic("genericDescription")) { valid = false; LoggingUtil.LogError(this, ErrorPrefix() + ": The field 'genericDescription' must be deterministic."); } // Sorting key valid &= ConfigNodeUtil.ParseValue <string>(configNode, "sortKey", x => sortKey = x, this, genericTitle); // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, this); if (valid) { LoggingUtil.LogInfo(this, "Successfully loaded CONTRACT_TYPE '" + name + "'"); } else { LoggingUtil.LogWarning(this, "Errors encountered while trying to load CONTRACT_TYPE '" + name + "'"); } config = configNode.ToString(); hash = config.GetHashCode(); enabled = valid; log += LoggingUtil.capturedLog; if (LoggingUtil.logLevel >= LoggingUtil.LogLevel.DEBUG) { // Get the contract configurator log file string[] dirComponents = new string[] { KSPUtil.ApplicationRootPath, "GameData", "ContractConfigurator", "log", (group == null ? "!NO_GROUP" : group.Root.name) }; string[] pathComponents = dirComponents.Union(new string[] { name + ".log" }).ToArray(); string dir = string.Join(Path.DirectorySeparatorChar.ToString(), dirComponents); string path = string.Join(Path.DirectorySeparatorChar.ToString(), pathComponents); // Delete the file if it exists if (File.Exists(path)) { try { File.Delete(path); } catch (Exception e) { LoggingUtil.LogException(new Exception("Exception while attempting to delete the file: " + path, e)); } } // Create the directory if it doesn't exist Directory.CreateDirectory(dir); // Now write the config and the cleaned up log to it try { using (StreamWriter sw = File.AppendText(path)) { sw.Write("Debug information for CONTRACT_TYPE '" + name + "':\n"); sw.Write("\nConfiguration:\n"); sw.Write(config); sw.Write("\nData Nodes:\n"); sw.Write(DataNodeDebug(dataNode)); sw.Write("\nOutput log:\n"); sw.Write(log); } } catch { LoggingUtil.LogError(this, "Exception while attempting to write to the file: " + path); } } return(valid); } catch (Exception e) { enabled = false; throw new Exception("Error loading CONTRACT_TYPE '" + name + "'", e); } finally { LoggingUtil.CaptureLog = false; LoggingUtil.logLevel = origLogLevel; loaded = true; } }