public override bool MeetRequirements() { // ContractType already chosen, check if still meets requirements. if (contractType != null) { bool meets = contractType.MeetRequirements(this, contractType); if (ContractState == State.Offered && !meets) { LoggingUtil.LogWarning(this, "Cancelled contract '" + title + "', as it no longer meets the requirements."); } if (ContractState == State.Active && !meets) { LoggingUtil.LogWarning(this, "Removed contract '" + title + "', as it no longer meets the requirements."); } return(meets); } else if (ContractState == State.Withdrawn) { // Special case for pre-loader return(true); } // No ContractType chosen return(false); }
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 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> /// Validates that the given config node does NOT contain the given value. /// </summary> /// <param name="configNode">The ConfigNode to check.</param> /// <param name="field">The field to exclude</param> /// <param name="obj">IContractConfiguratorFactory object for error reporting</param> /// <returns>Always true, but logs a warning for an unexpected value.</returns> public static bool ValidateExcludedValue(ConfigNode configNode, string field, IContractConfiguratorFactory obj) { if (configNode.HasNode(field) || configNode.HasValue(field)) { LoggingUtil.LogWarning(obj.GetType(), "{0}: unexpected entry '{1}' found, ignored.", obj.ErrorPrefix(), field); } return(true); }
public override bool Load(ConfigNode configNode) { // Load base class bool valid = base.Load(configNode); valid &= ValidateTargetBody(configNode); LoggingUtil.LogWarning(this, "EnterSOI is obsolete as of Contract Configurator 0.7.5 and will be removed in 1.0.0. Please use Orbit or ReachState instead."); return(valid); }
public override bool Load(ConfigNode configNode) { // Load base class bool valid = base.Load(configNode); valid &= ConfigNodeUtil.ParseValue <FlightLog.EntryType>(configNode, "situation", x => situation = x, this); valid &= ValidateTargetBody(configNode); LoggingUtil.LogWarning(this, "VesselHasVisited is obsolete as of Contract Configurator 0.7.5 and will be removed in 1.0.0. Please use Orbit or ReachState (with disableOnStateChange = true) instead."); return(valid); }
/// <summary> /// Disables standard contract types as requested by contract packs. /// </summary> /// <returns>True if the disabling is done.</returns> public static bool DisableContracts() { if (contractsDisabled) { return(true); } // Don't do anything if the contract system has not yet loaded if (ContractSystem.ContractTypes == null) { return(false); } LoggingUtil.LogDebug(typeof(ContractDisabler), "Disabling contract types..."); ConfigNode[] nodes = GameDatabase.Instance.GetConfigNodes("CONTRACT_CONFIGURATOR"); int disabledCounter = 0; // Start disabling via legacy method Dictionary <string, Type> contractsToDisable = new Dictionary <string, Type>(); foreach (ConfigNode node in nodes) { foreach (string contractType in node.GetValues("disabledContractType")) { LoggingUtil.LogWarning(typeof(ContractDisabler), "Disabling contract " + contractType + " via legacy method. Recommend using the disableContractType attribute of the CONTRACT_GROUP node instead."); if (SetContractToDisabled(contractType, null)) { disabledCounter++; } } } // Disable via new method foreach (ContractGroup contractGroup in ContractGroup.AllGroups.Where(g => g != null && g.parent == null)) { foreach (string contractType in contractGroup.disabledContractType) { if (SetContractToDisabled(contractType, contractGroup)) { disabledCounter++; } } } LoggingUtil.LogInfo(typeof(ContractDisabler), "Disabled " + disabledCounter + " ContractTypes."); contractsDisabled = true; return(true); }
public override bool RequirementMet(ConfiguredContract contract) { // Cache the tech tree if (techTree == null) { ConfigNode techTreeRoot = ConfigNode.Load(HighLogic.CurrentGame.Parameters.Career.TechTreeUrl); if (techTreeRoot != null) { techTree = techTreeRoot.GetNode("TechTree"); } if (techTreeRoot == null || techTree == null) { LoggingUtil.LogError(this, "Couldn't load tech tree from " + HighLogic.CurrentGame.Parameters.Career.TechTreeUrl); return(false); } } foreach (string tech in techs) { ConfigNode techNode = techTree.GetNodes("RDNode").Where(n => n.GetValue("id") == tech).FirstOrDefault(); if (techNode == null) { LoggingUtil.LogWarning(this, "No tech node found with id '" + tech + "'"); return(false); } // Get the state of the parents, as well as the anyToUnlock flag bool anyToUnlock = ConfigNodeUtil.ParseValue <bool>(techNode, "anyToUnlock"); IEnumerable <bool> parentsUnlocked = techNode.GetNodes("Parent"). Select(n => ResearchAndDevelopment.Instance.GetTechState(n.GetValue("parentID"))). Select(p => p != null && p.state == RDTech.State.Available); // Check if the parents have met the unlock criteria if (anyToUnlock && parentsUnlocked.Any(unlocked => unlocked) || !anyToUnlock && parentsUnlocked.All(unlocked => unlocked)) { continue; } else { return(false); } } return(true); }
/// <summary> /// Method for generating ContractParameter objects. This will call the Generate() method /// on the sub-class, load all common parameters and load child parameters. /// </summary> /// <param name="contract">Contract to generate for</param> /// <param name="contractParamHost">Parent object for the ContractParameter</param> /// <returns>Generated ContractParameter</returns> public virtual ContractParameter Generate(ConfiguredContract contract, IContractParameterHost contractParamHost) { // First check any requirements if (!ContractRequirement.RequirementsMet(contract, contract.contractType, requirements)) { LoggingUtil.LogVerbose(typeof(ParameterFactory), "Returning null for " + contract.contractType.name + "." + name + ": requirements not met."); return(null); } // Generate a parameter using the sub-class logic ContractParameter parameter = Generate(contract); if (parameter == null) { LoggingUtil.LogWarning(this, GetType().FullName + ".Generate() returned a null ContractParameter!"); return(null); } // Add ContractParameter to the host contractParamHost.AddParameter(parameter); // Set the funds/science/reputation parameters parameter.SetFunds(rewardFunds, failureFunds, targetBody); parameter.SetReputation(rewardReputation, failureReputation, targetBody); parameter.SetScience(rewardScience, targetBody); // Set other flags parameter.Optional = optional; if (disableOnStateChange != null) { parameter.DisableOnStateChange = (bool)disableOnStateChange; } parameter.ID = name; // Special stuff for contract configurator parameters ContractConfiguratorParameter ccParam = parameter as ContractConfiguratorParameter; if (ccParam != null) { ccParam.completeInSequence = completeInSequence; ccParam.notes = notes; ccParam.completedMessage = completedMessage; ccParam.hidden = hidden; ccParam.hideChildren = hideChildren; } return(parameter); }
public override bool Load(ConfigNode configNode) { // Load base class bool valid = base.Load(configNode); if (configNode.HasValue("vesselKey")) { LoggingUtil.LogWarning(this, "The 'vesselKey' attribute is obsolete as of Contract Configurator 0.7.5. It will be removed in 1.0.0 in favour of the vessel attribute."); valid &= ConfigNodeUtil.ParseValue <VesselIdentifier>(configNode, "vesselKey", x => vesselKey = x, this); } else { valid &= ConfigNodeUtil.ParseValue <VesselIdentifier>(configNode, "vessel", x => vesselKey = x, this); } return(valid); }
/// <summary> /// Performs validation to check if the given config node has values that were not expected. /// </summary> /// <param name="configNode">The ConfigNode to check.</param> /// <param name="obj">IContractConfiguratorFactory object for error reporting</param> /// <returns>Always true, but logs a warning if unexpected keys were found</returns> public static bool ValidateUnexpectedValues(ConfigNode configNode, IContractConfiguratorFactory obj) { bool valid = true; if (!keysFound.ContainsKey(configNode)) { obj.hasWarnings = true; LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() + ": did not attempt to load values for ConfigNode!"); return(false); } Dictionary <string, int> found = keysFound[configNode]; foreach (ConfigNode.Value pair in configNode.values) { if (!found.ContainsKey(pair.name)) { obj.hasWarnings = true; LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() + ": unexpected attribute '" + pair.name + "' found, ignored."); } } foreach (ConfigNode child in configNode.nodes) { // Exceptions if (child.name == "PARAMETER" && (obj is ContractType || obj is ParameterFactory) || child.name == "REQUIREMENT" && (obj is ContractType || obj is ParameterFactory || obj is ContractRequirement) || child.name == "BEHAVIOUR" && (obj is ContractType) || child.name == "ORBIT" && (obj is Behaviour.OrbitGeneratorFactory || obj is Behaviour.SpawnVesselFactory || obj is Behaviour.SpawnKerbalFactory)) { continue; } if (!found.ContainsKey(child.name)) { obj.hasWarnings = true; LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() + ": unexpected child node '" + child.name + "' found, ignored."); } } return(valid); }
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 bool MeetRequirements() { // No ContractType chosen if (contractType == null) { return(SelectContractType()); } else { // ContractType already chosen, check if still meets requirements. bool meets = contractType.MeetRequirements(this); if (ContractState == State.Active && !meets) { LoggingUtil.LogWarning(this, "Removed contract '" + title + "', as it no longer meets the requirements."); } return(meets); } }
public static void SetContractToDisabled(string contract, ContractGroup group) { Type contractType = contractTypes.Where(t => t.Name == contract).FirstOrDefault(); if (contractType == null) { LoggingUtil.LogWarning(typeof(ContractDisabler), "Couldn't find ContractType '" + contract + "' to disable."); } if (!contractDetails.ContainsKey(contractType)) { contractDetails[contractType] = new ContractDetails(contractType); } ContractDetails details = contractDetails[contractType]; details.disablingGroups.AddUnique(group); SetContractState(contractType, false); }
/// <summary> /// Performs validation to check if the given config node has values that were not expected. /// </summary> /// <param name="configNode">The ConfigNode to check.</param> /// <param name="obj">IContractConfiguratorFactory object for error reporting</param> /// <returns>Always true, but logs a warning if unexpected keys were found</returns> public static bool ValidateUnexpectedValues(ConfigNode configNode, IContractConfiguratorFactory obj) { if (!keysFound.ContainsKey(configNode)) { LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() + ": did not attempt to load values for ConfigNode!"); return(false); } Dictionary <string, int> found = keysFound[configNode]; foreach (ConfigNode.Value pair in configNode.values) { if (!found.ContainsKey(pair.name)) { LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() + ": unexpected entry '" + pair.name + "' found, ignored."); } } return(true); }
public static List <Type> GetAllTypes <T>() { // Get everything that extends ParameterFactory List <Type> allTypes = new List <Type>(); foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { try { foreach (Type t in from type in assembly.GetTypes() where type.IsSubclassOf(typeof(T)) select type) { allTypes.Add(t); } } catch (Exception e) { LoggingUtil.LogWarning(typeof(ContractConfigurator), "Error loading types from assembly " + assembly.FullName + ": " + e.Message); } } return(allTypes); }
/// <summary> /// Verifies that the contract group is not empty. /// </summary> public void CheckEmpty() { bool atLeastOne = false; foreach (ContractType contractType in ContractType.AllContractTypes.Where(ct => ct.group == this)) { atLeastOne = true; break; } // Need at least one contract in the group if (!atLeastOne) { // Try for a child group if (!ContractGroup.AllGroups.Where(g => g != null && g.parent != null && g.parent.name == name).Any()) { LoggingUtil.CaptureLog = true; LoggingUtil.LogWarning(this, "Contract group '" + name + "' contains no contract types or child groups!"); log += LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; hasWarnings = true; } } }
/// <summary> /// Generates a new ParameterFactory from the given ConfigNode. /// </summary> /// <param name="parameterConfig">ConfigNode to use in the generation.</param> /// <param name="contractType">ContractType that this parameter factory falls under</param> /// <param name="paramFactory">The ParameterFactory object.</param> /// <param name="parent">ParameterFactory to use as the parent</param> /// <returns>Whether the load was successful</returns> public static bool GenerateParameterFactory(ConfigNode parameterConfig, ContractType contractType, out ParameterFactory paramFactory, ParameterFactory parent = null) { // Logging on LoggingUtil.CaptureLog = true; bool valid = true; // Get the type string type = parameterConfig.GetValue("type"); string name = parameterConfig.HasValue("name") ? parameterConfig.GetValue("name") : type; if (string.IsNullOrEmpty(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "PARAMETER '" + parameterConfig.GetValue("name") + "' does not specify the mandatory 'type' attribute."); paramFactory = new InvalidParameterFactory(); valid = false; } else if (!factories.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "PARAMETER '" + parameterConfig.GetValue("name") + "' of type '" + parameterConfig.GetValue("type") + "': " + "Unknown parameter '" + type + "'."); paramFactory = new InvalidParameterFactory(); valid = false; } else { // Create an instance of the factory paramFactory = (ParameterFactory)Activator.CreateInstance(factories[type]); } // Set attributes paramFactory.parent = parent; paramFactory.contractType = contractType; paramFactory.dataNode = new DataNode(name, parent != null ? parent.dataNode : contractType.dataNode, paramFactory); // Load child requirements foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(parameterConfig, "REQUIREMENT")) { ContractRequirement req = null; valid &= ContractRequirement.GenerateRequirement(childNode, contractType, out req, paramFactory); if (req != null) { paramFactory.requirements.Add(req); if (req.hasWarnings) { paramFactory.hasWarnings = true; } } } // Load config if (!paramFactory.Load(parameterConfig)) { // If there was a load failure, check if there are requirements if (paramFactory.requirements.Count > 0) { LoggingUtil.LogWarning(paramFactory, "Ignoring failed parameter with child requirements."); } else { valid = false; } } // Late initialize for iterator keys valid &= DataNode.InitializeIteratorKey(parameterConfig, paramFactory); // Check for unexpected values - always do this last if (paramFactory.GetType() != typeof(InvalidParameterFactory)) { valid &= ConfigNodeUtil.ValidateUnexpectedValues(parameterConfig, paramFactory); } paramFactory.log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; // Load child nodes foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(parameterConfig, "PARAMETER")) { ParameterFactory child = null; valid &= ParameterFactory.GenerateParameterFactory(childNode, contractType, out child, paramFactory); if (child != null) { paramFactory.childNodes.Add(child); if (child.hasWarnings) { paramFactory.hasWarnings = true; } } } paramFactory.enabled = valid; 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) { try { // Logging on LoggingUtil.CaptureLog = true; dataNode = new DataNode(configNode.GetValue("name"), this); ConfigNodeUtil.ClearCache(true); ConfigNodeUtil.SetCurrentDataNode(dataNode); bool valid = true; valid &= ConfigNodeUtil.ParseValue <string>(configNode, "name", x => name = x, this); // 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 <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)); // TODO - these are to be deprecated if (configNode.HasValue("targetBodies")) { valid &= ConfigNodeUtil.ParseValue <List <CelestialBody> >(configNode, "targetBodies", x => targetBodies = x, this, new List <CelestialBody>()); LoggingUtil.LogWarning(this, "The 'targetBodies' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } if (configNode.HasValue("targetVessel")) { valid &= ConfigNodeUtil.ParseValue <Vessel>(configNode, "targetVessel", x => targetVessel = x, this, (Vessel)null); LoggingUtil.LogWarning(this, "The 'targetVessel' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } if (configNode.HasValue("targetVessels")) { valid &= ConfigNodeUtil.ParseValue <List <Vessel> >(configNode, "targetVessels", x => targetVessels = x, this, new List <Vessel>()); LoggingUtil.LogWarning(this, "The 'targetVessels' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } if (configNode.HasValue("targetKerbal")) { valid &= ConfigNodeUtil.ParseValue <Kerbal>(configNode, "targetKerbal", x => targetKerbal = x, this, (Kerbal)null); LoggingUtil.LogWarning(this, "The 'targetKerbal' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } if (configNode.HasValue("targetKerbals")) { valid &= ConfigNodeUtil.ParseValue <List <Kerbal> >(configNode, "targetKerbals", x => targetKerbals = x, this, new List <Kerbal>()); LoggingUtil.LogWarning(this, "The 'targetKerbals' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } // Load DATA nodes foreach (ConfigNode data in ConfigNodeUtil.GetChildNodes(configNode, "DATA")) { Type type = null; bool requiredValue = true; valid &= ConfigNodeUtil.ParseValue <Type>(data, "type", x => type = x, this); valid &= ConfigNodeUtil.ParseValue <bool>(data, "requiredValue", x => requiredValue = x, this, true); if (type != null) { foreach (ConfigNode.Value pair in data.values) { string name = pair.name; if (name != "type" && name != "requiredValue") { object value = null; // Create the setter function Type actionType = typeof(Action <>).MakeGenericType(type); Delegate del = Delegate.CreateDelegate(actionType, value, typeof(ContractType).GetMethod("NullAction")); // Get the ParseValue method MethodInfo method = typeof(ConfigNodeUtil).GetMethods(BindingFlags.Static | BindingFlags.Public). Where(m => m.Name == "ParseValue" && m.GetParameters().Count() == 4).Single(); method = method.MakeGenericMethod(new Type[] { type }); // Invoke the ParseValue method valid &= (bool)method.Invoke(null, new object[] { data, name, del, this }); dataValues[name] = requiredValue; } } } } // 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; } }
/// <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)); }
/// <summary> /// Performs adjustments to the contract type list. Specifically, disables contract types /// as per configuration files and adds addtional ConfiguredContract instances based on the /// number on contract types. /// </summary> /// <returns>Whether the changes took place</returns> bool AdjustContractTypes() { // Don't do anything if the contract system has not yet loaded if (ContractSystem.ContractTypes == null) { return(false); } LoggingUtil.LogDebug(this.GetType(), "Loading CONTRACT_CONFIGURATOR nodes."); ConfigNode[] nodes = GameDatabase.Instance.GetConfigNodes("CONTRACT_CONFIGURATOR"); // Build a unique list of contract types to disable, in case multiple mods try to // disable the same ones. Dictionary <string, Type> contractsToDisable = new Dictionary <string, Type>(); foreach (ConfigNode node in nodes) { foreach (string contractType in node.GetValues("disabledContractType")) { // No type for now contractsToDisable[contractType] = null; } } // Map the string to a type foreach (Type subclass in GetAllTypes <Contract>()) { string name = subclass.Name; if (contractsToDisable.ContainsKey(name)) { contractsToDisable[name] = subclass; } } // Start disabling! int disabledCounter = 0; foreach (KeyValuePair <string, Type> p in contractsToDisable) { // Didn't find a type if (p.Value == null) { LoggingUtil.LogWarning(this.GetType(), "Couldn't find ContractType '" + p.Key + "' to disable."); } else { LoggingUtil.LogDebug(this.GetType(), "Disabling ContractType: " + p.Value.FullName + " (" + p.Value.Module + ")"); ContractSystem.ContractTypes.Remove(p.Value); disabledCounter++; } } LoggingUtil.LogInfo(this.GetType(), "Disabled " + disabledCounter + " ContractTypes."); // Now add the ConfiguredContract type int count = (int)(ContractType.AllValidContractTypes.Count() / 3.0 + 0.5); for (int i = 0; i < count; i++) { ContractSystem.ContractTypes.Add(typeof(ConfiguredContract)); } LoggingUtil.LogInfo(this.GetType(), "Finished Adjusting ContractTypes"); return(true); }
public override ContractParameter Generate(Contract contract) { LoggingUtil.LogWarning(this, "ReachSpace is obsolete since Contract Configurator 1.7.7, use ReachState instead."); return(new ReachSpaceCustom(title)); }
public override ContractParameter Generate(Contract contract) { LoggingUtil.LogWarning(this, "SequenceNode is obsolete as of Contract Configurator 0.6.7, please use the completeInSequence attribute instead."); return(new Parameters.SequenceNode(title)); }
/// <summary> /// Checks if the "extended" requirements that change due to expressions. /// </summary> /// <param name="contract">The contract</param> /// <returns>Whether the contract can be offered.</returns> public bool MeetExtendedRequirements(ConfiguredContract contract, ContractType contractType) { LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel; try { // Turn tracing on if (trace) { LoggingUtil.logLevel = LoggingUtil.LogLevel.VERBOSE; LoggingUtil.LogWarning(this, "Tracing enabled for contract type " + name); } // Hash check if (contract.ContractState == Contract.State.Offered && contract.hash != hash) { throw new ContractRequirementException("Contract definition changed."); } // Check prestige if (prestige.Count > 0 && !prestige.Contains(contract.Prestige)) { throw new ContractRequirementException("Wrong prestige level."); } // Do a Research Bodies check, if applicable ResearchBodiesCheck(contract); // Check special values are not null if (contract.contractType == null) { foreach (KeyValuePair <string, DataValueInfo> pair in dataValues) { // Only check if it is a required value if (pair.Value.required) { CheckRequiredValue(pair.Key); } } } if (contract.contractType == null || contract.ContractState == Contract.State.Generated || contract.ContractState == Contract.State.Withdrawn) { // Check for unique values against other contracts of the same type foreach (KeyValuePair <string, DataNode.UniquenessCheck> pair in uniquenessChecks.Where(p => contract.uniqueData.ContainsKey(p.Key))) { string key = pair.Key; DataNode.UniquenessCheck uniquenessCheck = pair.Value; LoggingUtil.LogVerbose(this, "Doing unique value check for " + key); // Get the active/offered contract lists IEnumerable <ConfiguredContract> contractList = ConfiguredContract.CurrentContracts. Where(c => c != null && c.contractType != null && c != contract); // Add in finished contracts if (uniquenessCheck == DataNode.UniquenessCheck.CONTRACT_ALL || uniquenessCheck == DataNode.UniquenessCheck.GROUP_ALL) { contractList = contractList.Union(ContractSystem.Instance.ContractsFinished.OfType <ConfiguredContract>(). Where(c => c != null && c.contractType != null && c != contract)); } // 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 == 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); } object val = contract.uniqueData[key]; if (val != null) { // Special case for vessels - convert to the Guid Vessel vessel = val as Vessel; if (vessel != null) { val = vessel.id; } foreach (ConfiguredContract otherContract in contractList) { if (val.Equals(otherContract.uniqueData[key])) { throw new ContractRequirementException("Failed on unique value check for key '" + key + "'."); } } } } } // Check the captured requirements if (!ContractRequirement.RequirementsMet(contract, this, contract.requirements != null ? contract.requirements : requirements)) { throw new ContractRequirementException("Failed on contract requirement check."); } return(true); } catch (ContractRequirementException e) { LoggingUtil.LogLevel level = contract.ContractState == Contract.State.Active ? LoggingUtil.LogLevel.INFO : contract.contractType != null ? LoggingUtil.LogLevel.DEBUG : LoggingUtil.LogLevel.VERBOSE; string prefix = contract.contractType != null ? "Cancelling contract of type " + name + " (" + contract.Title + "): " : "Didn't generate contract of type " + name + ": "; LoggingUtil.Log(level, this.GetType(), prefix + e.Message); return(false); } catch { LoggingUtil.LogError(this, "Exception while attempting to check requirements of contract type " + name); throw; } finally { LoggingUtil.logLevel = origLogLevel; loaded = true; } }
/// <summary> /// Checks if the "basic" requirements that shouldn't change due to expressions are met. /// </summary> /// <param name="contract">The contract</param> /// <returns>Whether the contract can be offered.</returns> public bool MeetBasicRequirements(ConfiguredContract contract) { LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel; try { // Turn tracing on if (trace) { LoggingUtil.logLevel = LoggingUtil.LogLevel.VERBOSE; LoggingUtil.LogWarning(this, "Tracing enabled for contract type " + name); } // Check funding if (advanceFunds < 0) { CurrencyModifierQuery q = new CurrencyModifierQuery(TransactionReasons.ContractAdvance, -advanceFunds, 0.0f, 0.0f); GameEvents.Modifiers.OnCurrencyModifierQuery.Fire(q); float fundsRequired = advanceFunds + q.GetEffectDelta(Currency.Funds); if (!Funding.CanAfford(fundsRequired)) { throw new ContractRequirementException("Can't afford contract advance cost."); } } // Check expiry if ((contract.ContractState == Contract.State.Offered || contract.ContractState == Contract.State.Withdrawn) && Planetarium.fetch != null && contract.DateExpire < Planetarium.fetch.time) { throw new ContractRequirementException("Expired contract."); } // Checks for maxSimultaneous/maxCompletions if (maxSimultaneous != 0 || maxCompletions != 0) { IEnumerable <ConfiguredContract> contractList = ConfiguredContract.CurrentContracts. Where(c => c.contractType != null && c.contractType.name == name && c != contract); // Check if we're breaching the active limit int activeContracts = contractList.Count(); if (maxSimultaneous != 0 && activeContracts >= maxSimultaneous) { throw new ContractRequirementException("Too many active contracts."); } // Check if we're breaching the completed limit if (maxCompletions != 0) { if (ActualCompletions() + activeContracts >= maxCompletions) { throw new ContractRequirementException("Too many completed/active/offered contracts."); } } } // Check the group values if (group != null) { CheckContractGroup(contract, group); } return(true); } catch (ContractRequirementException e) { LoggingUtil.LogLevel level = contract.ContractState == Contract.State.Active ? LoggingUtil.LogLevel.INFO : contract.contractType != null ? LoggingUtil.LogLevel.DEBUG : LoggingUtil.LogLevel.VERBOSE; string prefix = contract.contractType != null ? "Cancelling contract of type " + name + " (" + contract.Title + "): " : "Didn't generate contract of type " + name + ": "; LoggingUtil.Log(level, this.GetType(), prefix + e.Message); return(false); } catch { LoggingUtil.LogError(this, "Exception while attempting to check requirements of contract type " + name); throw; } finally { LoggingUtil.logLevel = origLogLevel; loaded = true; } }
/// <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; } }
/// <summary> /// Loads debugging configurations. /// </summary> public static void LoadDebuggingConfig() { Debug.Log("[INFO] ContractConfigurator.LoggingUtil: Loading DebuggingConfig node."); // Don't know why .GetConfigNode("CC_DEBUGGING") returns null, using .GetConfigNodes("CC_DEBUGGING") works fine. ConfigNode[] debuggingConfigs = GameDatabase.Instance.GetConfigNodes("CC_DEBUGGING"); if (debuggingConfigs.Length > 0) { try { // Fetch config ConfigNode debuggingConfig = debuggingConfigs[0]; // Set LogLevel if (debuggingConfig.HasValue("logLevel")) { LoggingUtil.logLevel = (LoggingUtil.LogLevel)Enum.Parse(typeof(LoggingUtil.LogLevel), debuggingConfig.GetValue("logLevel")); LoggingUtil.LogInfo(typeof(LoggingUtil), "Set LogLevel = " + LoggingUtil.logLevel); } // Fetch specific loglevels for given types foreach (ConfigNode levelExceptionNode in debuggingConfig.GetNodes("ADD_LOGLEVEL_EXCEPTION")) { if (levelExceptionNode.HasValue("type") && levelExceptionNode.HasValue("logLevel")) { // Fetch full type name - just search and find the matching one while // ignoring namespace string typeName = levelExceptionNode.GetValue("type"); Type type = null; foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { try { foreach (Type t in a.GetTypes()) { if (t.Name == typeName || t.Name.StartsWith(typeName + '`')) { type = t; break; } } } catch (Exception e) { Debug.LogWarning("[WARNING] Error loading types from assembly " + a.FullName + ": " + e.Message); } } if (type != null) { LoggingUtil.LogLevel logLevel = (LoggingUtil.LogLevel)Enum.Parse(typeof(LoggingUtil.LogLevel), levelExceptionNode.GetValue("logLevel")); LoggingUtil.AddSpecificLogLevel(type, logLevel); } else { Debug.LogWarning("[WARNING] ContractConfigurator.LoggingUtil: Couldn't find Type with name: '" + typeName + "'"); } } else { Debug.LogWarning("[WARNING] ContractConfigurator.LoggingUtil: Couldn't load specific LogLevel node, type or logLevel not given!"); } } LoggingUtil.LogInfo(typeof(LoggingUtil), "DebugingConfig loaded!"); } catch (Exception e) { LoggingUtil.ClearSpecificLogLevel(); LoggingUtil.logLevel = LoggingUtil.LogLevel.INFO; LoggingUtil.LogWarning(typeof(LoggingUtil), "Debugging Config failed to load! Message: '" + e.Message + "' Set LogLevel to INFO and cleaned specific LogLevels"); } } else { LoggingUtil.logLevel = LoggingUtil.LogLevel.INFO; LoggingUtil.LogWarning(typeof(LoggingUtil), "No debugging config found! LogLevel set to INFO"); } }
void Update() { // Detect if there are any new messages if (MessageSystem.Instance != null) { // Derive the internal message list if (messageList == null) { messageList = (List <MessageSystemButton>)messageListField.GetValue(MessageSystem.Instance); } // Go through new messages if (messageList.Count > lastMessageCount) { for (int i = (messageList.Count - lastMessageCount); i-- > 0;) { LoggingUtil.LogVerbose(this, "Message list count = {0}, message {3} = {1} + {2}", messageList.Count, messageList[i].message.message, messageList[i].message.messageTitle, i); if (LocalizationUtil.IsLocalizedString(messageList[i].message.message, deployedScienceTag)) { // Pull out the parameters IList <string> parameters = LocalizationUtil.UnLocalizeString(messageList[i].message.message, deployedScienceTag); // Identify the subject ScienceSubject subject = null; foreach (ScienceSubject sub in recentScience) { if (sub.title == parameters[0]) { subject = sub; break; } } // Subject identified if (subject != null) { LoggingUtil.LogVerbose(this, "Subject identified as {0}", subject.id); // Delete the old message MessageSystem.Instance.DiscardMessage(messageList[i].message.button); // Check for an existing summary level message MessageSystem.Message message = MessageSystem.Instance.FindMessages(m => m.messageTitle == deployedScienceMessageTitle).FirstOrDefault(); if (message != null) { message.IsRead = false; trackedSubjects.Clear(); } trackedSubjects.Add(subject); trackedSubjects.Sort((ss1, ss2) => string.Compare(ss1.title, ss2.title)); StringBuilder sb = StringBuilderCache.Acquire(); sb.Append(string.Format("<b>{0}</b>:\n", deployedScienceMessageTitle)); foreach (ScienceSubject s in trackedSubjects) { sb.Append(string.Format(" {0}: <color=#6DCFF6><sprite=\"CurrencySpriteAsset\" name=\"Science\" tint=1> {1}</color> / <color=#6DCFF6><sprite=\"CurrencySpriteAsset\" name=\"Science\" tint=1> {2}</color>\n", s.title, s.science.ToString("F1"), s.scienceCap.ToString("F1"))); } if (message != null) { message.message = sb.ToStringAndRelease(); } else { MessageSystem.Instance.AddMessage(new MessageSystem.Message(deployedScienceMessageTitle, sb.ToStringAndRelease(), MessageSystemButton.MessageButtonColor.BLUE, MessageSystemButton.ButtonIcons.ALERT)); } } else { LoggingUtil.LogWarning(this, "Couldn't identify subject for deployed experiment with title '{0}'", parameters[0]); } } } recentScience.Clear(); } lastMessageCount = messageList.Count; // Check for active screen messages screenMessagesToRemove.Clear(); foreach (ScreenMessage message in ScreenMessages.Instance.ActiveMessages) { if (LocalizationUtil.IsLocalizedString(message.message, deployedScienceTag)) { screenMessagesToRemove.Add(message); } } // Remove the messages foreach (ScreenMessage message in screenMessagesToRemove) { ScreenMessages.RemoveMessage(message); } } }
/// <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 => 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 => {}, 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; } }
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 { } } }