/* * Generates a ContractRequirement from a configuration node. */ public static ContractRequirement GenerateRequirement(ConfigNode configNode, ContractType contractType) { // Get the type string type = configNode.GetValue("type"); if (!requirementTypes.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "REQUIREMENT '" + configNode.GetValue("name") + "' of type '" + configNode.GetValue("type") + "': " + "No ContractRequirement has been registered for type '" + type + "'."); return(null); } // Create an instance of the ContractRequirement ContractRequirement requirement = (ContractRequirement)Activator.CreateInstance(requirementTypes[type]); // Set attributes requirement.contractType = contractType; requirement.targetBody = contractType.targetBody; // Load config bool valid = requirement.Load(configNode); // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, requirement); return(valid ? requirement : null); }
/* * Checks if all the given ContractRequirement meet the requirement. */ public static bool RequirementsMet(ConfiguredContract contract, ContractType contractType, List <ContractRequirement> contractRequirements) { bool allReqMet = true; try { LoggingUtil.LogVerbose(typeof(ContractRequirement), "Checking requirements for contract '" + contractType.name); foreach (ContractRequirement requirement in contractRequirements) { if (requirement.checkOnActiveContract || contract.ContractState != Contract.State.Active) { bool nodeMet = requirement.RequirementMet(contract); LoggingUtil.LogVerbose(typeof(ContractRequirement), "Checked requirement '" + requirement.name + "' of type " + requirement.type + ": " + nodeMet); allReqMet = allReqMet && (requirement.invertRequirement ? !nodeMet : nodeMet); } } // Force fail the contract if a requirement becomes unmet if (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) { Debug.LogException(new Exception("ContractConfigurator: Exception checking requirements!", e)); return(false); } return(allReqMet); }
/// <summary> /// Generates a BehaviourFactory from a configuration node. /// </summary> /// <param name="behaviourConfig">ConfigNode to use in the generation.</param> /// <param name="contractType">ContractType that this behaviour falls under</param> /// <param name="behaviourFactory">The BehaviourFactory object.</param> /// <returns>Whether the load was successful</returns> public static bool GenerateBehaviourFactory(ConfigNode behaviourConfig, ContractType contractType, out BehaviourFactory behaviourFactory) { // Logging on LoggingUtil.CaptureLog = true; bool valid = true; // Get the type string type = behaviourConfig.GetValue("type"); string name = behaviourConfig.HasValue("name") ? behaviourConfig.GetValue("name") : type; if (string.IsNullOrEmpty(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "BEHAVIOUR '" + behaviourConfig.GetValue("name") + "' does not specify the mandatory 'type' attribute."); behaviourFactory = new InvalidBehaviourFactory(); valid = false; } else if (!factories.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "BEHAVIOUR '" + behaviourConfig.GetValue("name") + "' of type '" + behaviourConfig.GetValue("type") + "': " + "No BehaviourFactory has been registered for type '" + type + "'."); behaviourFactory = new InvalidBehaviourFactory(); valid = false; } else { // Create an instance of the factory behaviourFactory = (BehaviourFactory)Activator.CreateInstance(factories[type]); } // Set attributes behaviourFactory.contractType = contractType; behaviourFactory.dataNode = new DataNode(name, contractType.dataNode, behaviourFactory); // Load config valid &= behaviourFactory.Load(behaviourConfig); // Check for unexpected values - always do this last if (behaviourFactory.GetType() != typeof(InvalidBehaviourFactory)) { valid &= ConfigNodeUtil.ValidateUnexpectedValues(behaviourConfig, behaviourFactory); } behaviourFactory.enabled = valid; behaviourFactory.log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; return(valid); }
/// <summary> /// Generates a BehaviourFactory from a configuration node. /// </summary> /// <param name="behaviourConfig">ConfigNode to use in the generation.</param> /// <param name="contractType">ContractType that this behaviour falls under</param> /// <param name="behaviourFactory">The BehaviourFactory object.</param> /// <returns>Whether the load was successful</returns> public static bool GenerateBehaviourFactory(ConfigNode behaviourConfig, ContractType contractType, out BehaviourFactory behaviourFactory) { // Logging on LoggingUtil.CaptureLog = true; bool valid = true; // Get the type string type = behaviourConfig.GetValue("type"); string name = behaviourConfig.HasValue("name") ? behaviourConfig.GetValue("name") : type; if (string.IsNullOrEmpty(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "BEHAVIOUR '" + behaviourConfig.GetValue("name") + "' does not specify the mandatory 'type' attribute."); behaviourFactory = new InvalidBehaviourFactory(); valid = false; } else if (!factories.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "BEHAVIOUR '" + behaviourConfig.GetValue("name") + "' of type '" + behaviourConfig.GetValue("type") + "': " + "Unknown behaviour '" + type + "'."); behaviourFactory = new InvalidBehaviourFactory(); valid = false; } else { // Create an instance of the factory behaviourFactory = (BehaviourFactory)Activator.CreateInstance(factories[type]); } // Set attributes behaviourFactory.contractType = contractType; behaviourFactory.dataNode = new DataNode(name, contractType.dataNode, behaviourFactory); // Load config valid &= behaviourFactory.Load(behaviourConfig); // Check for unexpected values - always do this last if (behaviourFactory.GetType() != typeof(InvalidBehaviourFactory)) { valid &= ConfigNodeUtil.ValidateUnexpectedValues(behaviourConfig, behaviourFactory); } behaviourFactory.enabled = valid; behaviourFactory.log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; return valid; }
public override bool Load(ConfigNode configNode) { // Load base class bool valid = base.Load(configNode); // Get type string contractType = null; valid &= ConfigNodeUtil.ParseValue <string>(configNode, "contractType", x => contractType = x, this); if (valid) { if (ContractType.GetContractType(contractType) != null) { ccType = contractType; } else { ccType = null; // Search for the correct type var classes = from assembly in AppDomain.CurrentDomain.GetAssemblies() from type in assembly.GetTypes() where type.IsSubclassOf(typeof(Contract)) && type.Name.Equals(contractType) select type; if (classes.Count() < 1) { valid = false; LoggingUtil.LogError(this.GetType(), "contractType '" + contractType + "' must either be a Contract sub-class or ContractConfigurator contract type"); } else { contractClass = classes.First(); } } } valid &= ConfigNodeUtil.ParseValue <uint>(configNode, "minCount", x => minCount = x, this, 1); valid &= ConfigNodeUtil.ParseValue <uint>(configNode, "maxCount", x => maxCount = x, this, UInt32.MaxValue); valid &= ConfigNodeUtil.ParseValue <Duration>(configNode, "cooldownDuration", x => cooldownDuration = x, this, new Duration(0.0)); 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 { } } }
private static void BehaviourGui(ContractType contractType, IEnumerable <BehaviourFactory> behaviourList, int indent) { foreach (BehaviourFactory behaviour in behaviourList) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(false)); GUILayout.Space(28); GUILayout.Label(new GUIContent(new string(' ', indent * 4) + behaviour, DebugInfo(behaviour)), behaviour.enabled ? behaviour.hasWarnings ? yellowLabel : GUI.skin.label : redLabel); if (contractType.enabled) { if (GUILayout.Button(behaviour.enabled ? check : cross, GUILayout.ExpandWidth(false))) { behaviour.enabled = !behaviour.enabled; } } GUILayout.EndHorizontal(); } }
/// <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); }
/// <summary> /// Checks if the given contract type belongs to the given group /// </summary> /// <param name="contractType">The contract type to check</param> /// <returns>True if the contract type is a part of this group</returns> public bool BelongsToGroup(ContractType contractType) { if (contractType == null) { return(false); } ContractGroup group = contractType.group; while (group != null) { if (group.name == name) { return(true); } group = group.parent; } return(false); }
static GUIContent CurrencyGUIContent(Currency currency, ContractType contractType, double baseValue) { // Figure out the multiplier double multiplier = 1.0; if (contractType.targetBody != null) { multiplier *= GameVariables.Instance.GetContractDestinationWeight(contractType.targetBody); } string multInfo = baseValue.ToString("N0") + " (base) * " + multiplier.ToString("F1") + " (body)"; if (contractType.prestige.Count > 0) { double val = GameVariables.Instance.GetContractPrestigeFactor(contractType.prestige.First()); multiplier *= val; multInfo += " * " + val.ToString("F2") + " (prestige)"; } // Get the proper amount, add color double adjustedValue = multiplier * baseValue; string text = "<color=#"; switch (currency) { case Currency.Funds: text += "b4d455"; break; case Currency.Reputation: text += "e0d503"; break; case Currency.Science: text += "6dcff6"; break; } text += ">" + adjustedValue.ToString("N0") + "</color>"; // Return the gui content return(new GUIContent(text, multInfo)); }
private static void RequirementGui(ContractType contractType, IEnumerable <ContractRequirement> requirementList, int indent) { foreach (ContractRequirement requirement in requirementList) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(false)); GUILayout.Space(28); GUIStyle style = requirement.lastResult == null ? GUI.skin.label : requirement.lastResult.Value ? greenLabel : yellowLabel; GUILayout.Label(new GUIContent(new string(' ', indent * 4) + requirement, DebugInfo(requirement)), requirement.enabled ? requirement.hasWarnings ? yellowLabel : style : redLabel); if (contractType.enabled) { if (GUILayout.Button(requirement.enabled ? check : cross, GUILayout.ExpandWidth(false))) { requirement.enabled = !requirement.enabled; } } GUILayout.EndHorizontal(); RequirementGui(contractType, requirement.ChildRequirements, indent + 1); } }
private static void ParamGui(ContractType contractType, IEnumerable <ParameterFactory> paramList, int indent) { foreach (ParameterFactory param in paramList) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(false)); GUILayout.Space(28); GUILayout.Label(new GUIContent(new string(' ', indent * 4) + param, DebugInfo(param)), param.enabled ? param.hasWarnings ? yellowLabel : GUI.skin.label : redLabel); if (contractType.enabled) { if (GUILayout.Button(param.enabled ? check : cross, GUILayout.ExpandWidth(false))) { param.enabled = !param.enabled; } } GUILayout.EndHorizontal(); ParamGui(contractType, param.ChildParameters, indent + 1); RequirementGui(contractType, param.ChildRequirements, indent + 1); } }
protected string ContractTitle() { string contractTitle; if (ccType != null) { ContractType contractType = ContractType.AllValidContractTypes.Where(ct => ct.name == ccType).FirstOrDefault(); if (contractType != null) { contractTitle = contractType.genericTitle; } else { contractTitle = ccType; } } else { // TODO - normalize name contractTitle = contractClass.Name; } return(contractTitle); }
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(agent.Name, agent.GetMindsetString(), contractType.topic, contractType.subject, contractType.motivation, random.Next()); } 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; } }
/// <summary> /// Tests whether a contract can be offered. /// </summary> /// <param name="contract">The contract</param> /// <returns>Whether the contract can be offered.</returns> public bool MeetRequirements(ConfiguredContract contract, ContractType contractType) { return MeetBasicRequirements(contract) && MeetExtendedRequirements(contract, contractType); }
/// <summary> /// Tests whether a contract can be offered. /// </summary> /// <param name="contract">The contract</param> /// <returns>Whether the contract can be offered.</returns> public bool MeetRequirements(ConfiguredContract contract, ContractType contractType) { return(MeetBasicRequirements(contract) && MeetExtendedRequirements(contract, contractType)); }
/// <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> /// Generates a ContractRequirement from a configuration node. /// </summary> /// <param name="configNode">ConfigNode to use in the generation.</param> /// <param name="contractType">ContractType that this requirement falls under</param> /// <param name="requirement">The ContractRequirement object.</param> /// <returns>Whether the load was successful</returns> public static bool GenerateRequirement(ConfigNode configNode, ContractType contractType, out ContractRequirement requirement, IContractConfiguratorFactory parent = null) { // Logging on LoggingUtil.CaptureLog = true; bool valid = true; // Get the type string type = configNode.GetValue("type"); string name = configNode.HasValue("name") ? configNode.GetValue("name") : type; if (string.IsNullOrEmpty(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "REQUIREMENT '" + configNode.GetValue("name") + "' does not specify the mandatory 'type' attribute."); requirement = new InvalidContractRequirement(); valid = false; } else if (!requirementTypes.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "REQUIREMENT '" + configNode.GetValue("name") + "' of type '" + configNode.GetValue("type") + "': " + "Unknown requirement '" + type + "'."); requirement = new InvalidContractRequirement(); valid = false; } else { // Create an instance of the ContractRequirement requirement = (ContractRequirement)Activator.CreateInstance(requirementTypes[type]); } // Set attributes requirement.contractType = contractType; requirement.dataNode = new DataNode(name, parent != null ? parent.dataNode : contractType.dataNode, requirement); // Load config valid &= requirement.Load(configNode); // Check for unexpected values - always do this last if (requirement.GetType() != typeof(InvalidContractRequirement)) { valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, requirement); } // Load child nodes foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT")) { ContractRequirement child = null; valid &= ContractRequirement.GenerateRequirement(childNode, contractType, out child, requirement); if (child != null) { requirement.childNodes.Add(child); if (child.hasWarnings) { requirement.hasWarnings = true; } } } requirement.enabled = valid; requirement.log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; return valid; }
private IEnumerable<ConfiguredContract> GenerateContract(ContractType contractType) { // Set the desired prestige int t1, t2, t3; ContractSystem.GetContractCounts(Reputation.CurrentRep, 1000, out t1, out t2, out t3); if (contractType.prestige.Any()) { if (!contractType.prestige.Contains(Contract.ContractPrestige.Trivial)) { t1 = 0; } if (!contractType.prestige.Contains(Contract.ContractPrestige.Significant)) { t2 = 0; } if (!contractType.prestige.Contains(Contract.ContractPrestige.Exceptional)) { t3 = 0; } } int selection = rand.Next(0, t1 + t2 + t3); Contract.ContractPrestige prestige = selection < t1 ? Contract.ContractPrestige.Trivial : selection < t2 ? Contract.ContractPrestige.Significant : Contract.ContractPrestige.Exceptional; // Generate the template ConfiguredContract templateContract = Contract.Generate(typeof(ConfiguredContract), prestige, rand.Next(), Contract.State.Withdrawn) as ConfiguredContract; // First, check the basic requirements if (!contractType.MeetBasicRequirements(templateContract)) { LoggingUtil.LogVerbose(this, contractType.name + " was not generated: basic requirements not met."); if (++contractType.failedGenerationAttempts >= contractType.maxConsecutiveGenerationFailures) { contractType.lastGenerationFailure = Time.realtimeSinceStartup; } yield return null; yield break; } // Try to refresh non-deterministic values before we check extended requirements OnInitializeValues.Fire(); LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel; LoggingUtil.LogLevel newLogLevel = contractType.trace ? LoggingUtil.LogLevel.VERBOSE : LoggingUtil.logLevel; try { // Set up for loop LoggingUtil.logLevel = newLogLevel; ConfiguredContract.currentContract = templateContract; // Set up the iterator to refresh non-deterministic values IEnumerable<string> iter = ConfigNodeUtil.UpdateNonDeterministicValuesIterator(contractType.dataNode); for (ContractGroup g = contractType.group; g != null; g = g.parent) { iter = ConfigNodeUtil.UpdateNonDeterministicValuesIterator(g.dataNode).Concat(iter); } // Update the actual values LoggingUtil.LogVerbose(this, "Refresh non-deterministic values for CONTRACT_TYPE = " + contractType.name); foreach (string val in iter) { lastKey = contractType.name + "[" + val + "]"; // Clear temp stuff LoggingUtil.logLevel = origLogLevel; ConfiguredContract.currentContract = null; if (val == null) { LoggingUtil.LogVerbose(this, contractType.name + " was not generated: non-deterministic expression failure."); if (++contractType.failedGenerationAttempts >= contractType.maxConsecutiveGenerationFailures) { contractType.lastGenerationFailure = Time.realtimeSinceStartup; } OnInitializeFail.Fire(); yield return null; yield break; } else { // Quick pause yield return null; } // Re set up LoggingUtil.logLevel = newLogLevel; ConfiguredContract.currentContract = templateContract; } } finally { LoggingUtil.logLevel = origLogLevel; ConfiguredContract.currentContract = null; } // Store unique data foreach (string key in contractType.uniquenessChecks.Keys) { if (contractType.dataNode.GetType(key) == typeof(Vessel)) { Vessel v = contractType.dataNode[key] as Vessel; templateContract.uniqueData[key] = v != null ? (object)v.id : null; } else { templateContract.uniqueData[key] = contractType.dataNode[key]; } } templateContract.targetBody = contractType.targetBody; // Check the requirements for our selection if (contractType.MeetExtendedRequirements(templateContract, contractType) && templateContract.Initialize(contractType)) { templateContract.ContractState = Contract.State.Offered; yield return templateContract; } // Failure, add a pause in before finishing else { LoggingUtil.LogVerbose(this, contractType.name + " was not generated: requirement not met."); if (++contractType.failedGenerationAttempts >= contractType.maxConsecutiveGenerationFailures) { contractType.lastGenerationFailure = Time.realtimeSinceStartup; } OnInitializeFail.Fire(); yield return null; } }
/// <summary> /// Generates a ContractRequirement from a configuration node. /// </summary> /// <param name="configNode">ConfigNode to use in the generation.</param> /// <param name="contractType">ContractType that this requirement falls under</param> /// <param name="requirement">The ContractRequirement object.</param> /// <returns>Whether the load was successful</returns> public static bool GenerateRequirement(ConfigNode configNode, ContractType contractType, out ContractRequirement requirement, IContractConfiguratorFactory parent = null) { // Logging on LoggingUtil.CaptureLog = true; bool valid = true; // Get the type string type = configNode.GetValue("type"); string name = configNode.HasValue("name") ? configNode.GetValue("name") : type; if (string.IsNullOrEmpty(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "REQUIREMENT '" + configNode.GetValue("name") + "' does not specify the mandatory 'type' attribute."); requirement = new InvalidContractRequirement(); valid = false; } else if (!requirementTypes.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "REQUIREMENT '" + configNode.GetValue("name") + "' of type '" + configNode.GetValue("type") + "': " + "Unknown requirement '" + type + "'."); requirement = new InvalidContractRequirement(); valid = false; } else { // Create an instance of the ContractRequirement requirement = (ContractRequirement)Activator.CreateInstance(requirementTypes[type]); } // Set attributes requirement.contractType = contractType; requirement.dataNode = new DataNode(name, parent != null ? parent.dataNode : contractType.dataNode, requirement); // Load config valid &= requirement.LoadFromConfig(configNode); // Override the needsTitle if we have a parent node with hideChildren ContractRequirement parentRequirement = parent as ContractRequirement; if (parentRequirement != null) { if (parentRequirement.hideChildren) { requirement.hideChildren = true; requirement.needsTitle = false; } } // Check for unexpected values - always do this last if (requirement.GetType() != typeof(InvalidContractRequirement)) { valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, requirement); } // Load child nodes foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT")) { ContractRequirement child = null; valid &= ContractRequirement.GenerateRequirement(childNode, contractType, out child, requirement); if (child != null) { requirement.childNodes.Add(child); if (child.hasWarnings) { requirement.hasWarnings = true; } } } // Error for missing title if (requirement.needsTitle && string.IsNullOrEmpty(requirement.title)) { valid = contractType.minVersion < ContractConfigurator.ENHANCED_UI_VERSION; LoggingUtil.Log(contractType.minVersion >= ContractConfigurator.ENHANCED_UI_VERSION ? LoggingUtil.LogLevel.ERROR : LoggingUtil.LogLevel.WARNING, requirement, requirement.ErrorPrefix(configNode) + ": missing required attribute 'title'."); } requirement.enabled = valid; requirement.log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; return valid; }
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 { } } }
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; } }
private bool SelectContractType() { if (!lastSpecificGenerationFailure.ContainsKey(prestige)) { lastSpecificGenerationFailure[prestige] = 0; } LoggingUtil.LogVerbose(this, "Generating a contract for prestige = " + prestige); // Loop through all the contract groups IEnumerable <ContractGroup> groups = ContractGroup.AllGroups; foreach (ContractGroup group in groups.Skip(nextGroup).Concat(groups.Take(nextGroup))) { LoggingUtil.LogVerbose(this, "Looking at group " + group); nextGroup = (nextGroup + 1) % groups.Count(); // Build a weighted list of ContractTypes to choose from Dictionary <ContractType, double> validContractTypes = new Dictionary <ContractType, double>(); double totalWeight = 0.0; foreach (ContractType ct in ContractType.AllValidContractTypes.Where(ct => ct.group == group)) { LoggingUtil.LogVerbose(this, "Checking ContractType = " + ct.name); // KSP tries to generate new contracts *incessantly*, to the point where this becomes // a real performance problem. So if we run into a situation where we did not // generate a contract and we are asked AGAIN after a very short time, then do // some logic to prevent re-checking uselessly. // If there was any generation failure within the last 100 frames, only look at // contracts specific to that prestige level if (lastGenerationFailure + 100 > Time.frameCount) { // If there was a generation failure for this specific prestige level in // the last 100 frames, then just skip the checks entirely if (lastSpecificGenerationFailure[prestige] + 100 > Time.frameCount) { return(false); } } // Only select contracts with the correct prestige level if (ct.prestige.Count == 0 || ct.prestige.Contains(prestige)) { validContractTypes.Add(ct, ct.weight); totalWeight += ct.weight; } } // Loop until we either run out of contracts in our list or make a selection System.Random generator = new System.Random(this.MissionSeed); while (validContractTypes.Count > 0) { ContractType selectedContractType = null; // Pick one of the contract types based on their weight double value = generator.NextDouble() * totalWeight; foreach (KeyValuePair <ContractType, double> pair in validContractTypes) { value -= pair.Value; if (value <= 0.0) { selectedContractType = pair.Key; break; } } // Shouldn't happen, but floating point rounding could put us here if (selectedContractType == null) { selectedContractType = validContractTypes.First().Key; } // Try to refresh non-deterministic values before we check requirements currentContract = this; LoggingUtil.LogVerbose(this, "Refresh non-deterministic values for CONTRACT_TYPE = " + selectedContractType.name); if (!ConfigNodeUtil.UpdateNonDeterministicValues(selectedContractType.dataNode)) { LoggingUtil.LogVerbose(this, selectedContractType.name + " was not generated: non-deterministic expression failure."); validContractTypes.Remove(selectedContractType); totalWeight -= selectedContractType.weight; } currentContract = null; // Check the requirements for our selection if (selectedContractType.MeetRequirements(this)) { contractType = selectedContractType; subType = contractType.name; return(true); } // Remove the selection, and try again else { LoggingUtil.LogVerbose(this, selectedContractType.name + " was not generated: requirement not met."); validContractTypes.Remove(selectedContractType); totalWeight -= selectedContractType.weight; } } } // Set our failure markers lastGenerationFailure = Time.frameCount; lastSpecificGenerationFailure[prestige] = Time.frameCount; return(false); }
/// <summary> /// Clears the contract configuration. /// </summary> void ClearContractConfig() { ContractGroup.contractGroups.Clear(); ContractType.ClearContractTypes(); totalContracts = successContracts = attemptedContracts = 0; }
/// <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; } } // 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> /// Checks if the given contract type belongs to the given group /// </summary> /// <param name="contractType">The contract type to check</param> /// <returns>True if the contract type is a part of this group</returns> public bool BelongsToGroup(ContractType contractType) { if (contractType == null) { return false; } ContractGroup group = contractType.group; while (group != null) { if (group.name == name) { return true; } group = group.parent; } return false; }
/// <summary> /// Loads all the contact type nodes and creates ContractType objects. /// </summary> private IEnumerator <YieldInstruction> LoadContractTypeConfig() { LoggingUtil.LogDebug(this, "Loading CONTRACT_TYPE nodes."); ConfigNode[] contractConfigs = GameDatabase.Instance.GetConfigNodes("CONTRACT_TYPE"); totalContracts = contractConfigs.Count(); // First pass - create all the ContractType objects foreach (ConfigNode contractConfig in contractConfigs) { // Create the initial contract type LoggingUtil.LogVerbose(this, "Pre-load for node: '" + contractConfig.GetValue("name") + "'"); try { ContractType contractType = new ContractType(contractConfig.GetValue("name")); } catch (ArgumentException) { LoggingUtil.LogError(this, "Couldn't load CONTRACT_TYPE '" + contractConfig.GetValue("name") + "' due to a duplicate name."); } } // Second pass - do the actual loading of details foreach (ConfigNode contractConfig in contractConfigs) { attemptedContracts++; if (reloading) { yield return(new WaitForEndOfFrame()); } // Fetch the contractType string name = contractConfig.GetValue("name"); ContractType contractType = ContractType.GetContractType(name); if (contractType != null && !contractType.loaded) { // Perform the load try { contractType.Load(contractConfig); if (contractType.enabled) { successContracts++; } } catch (Exception e) { LoggingUtil.LogException(e); } } } LoggingUtil.LogInfo(this, "Loaded " + successContracts + " out of " + totalContracts + " CONTRACT_TYPE nodes."); // Check for empty groups and warn foreach (ContractGroup group in ContractGroup.contractGroups.Values.Where(g => g != null)) { group.CheckEmpty(); } // Load other things MissionControlUI.GroupContainer.LoadConfig(); if (!reloading && LoggingUtil.logLevel == LoggingUtil.LogLevel.DEBUG || LoggingUtil.logLevel == LoggingUtil.LogLevel.VERBOSE) { ScreenMessages.PostScreenMessage("Contract Configurator: Loaded " + successContracts + " out of " + totalContracts + " contracts successfully.", 5, ScreenMessageStyle.UPPER_CENTER); } }
/* * Generates a new ParameterFactory from the given ConfigNode. */ public static ParameterFactory GenerateParameterFactory(ConfigNode parameterConfig, ContractType contractType) { // Get the type string type = parameterConfig.GetValue("type"); if (!factories.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "PARAMETER '" + parameterConfig.GetValue("name") + "' of type '" + parameterConfig.GetValue("type") + "': " + "No ParameterFactory has been registered for type '" + type + "'."); return(null); } // Create an instance of the factory ParameterFactory paramFactory = (ParameterFactory)Activator.CreateInstance(factories[type]); // Set attributes paramFactory.contractType = contractType; // Load config bool valid = paramFactory.Load(parameterConfig); // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(parameterConfig, paramFactory); return(valid ? paramFactory : null); }
/// <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 '" + contractType.name); foreach (ContractRequirement requirement in contractRequirements) { if (requirement.enabled) { if (requirement.checkOnActiveContract || contract.ContractState != Contract.State.Active) { allReqMet = allReqMet && requirement.CheckRequirement(contract); if (!allReqMet) { LoggingUtil.Log(contract.ContractState == Contract.State.Active ? LoggingUtil.LogLevel.INFO : LoggingUtil.LogLevel.VERBOSE, requirement.GetType(), "Contract " + contractType.name + ": requirement " + requirement.name + " was not met."); break; } } } } // Force fail the contract if a requirement becomes unmet if (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; }
/// <summary> /// Generates a ContractRequirement from a configuration node. /// </summary> /// <param name="configNode">ConfigNode to use in the generation.</param> /// <param name="contractType">ContractType that this requirement falls under</param> /// <param name="requirement">The ContractRequirement object.</param> /// <returns>Whether the load was successful</returns> public static bool GenerateRequirement(ConfigNode configNode, ContractType contractType, out ContractRequirement requirement, IContractConfiguratorFactory parent = null) { // Logging on LoggingUtil.CaptureLog = true; bool valid = true; // Get the type string type = configNode.GetValue("type"); string name = configNode.HasValue("name") ? configNode.GetValue("name") : type; if (string.IsNullOrEmpty(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '{0}', REQUIREMENT '{1}' does not specify the mandatory 'type' attribute.", contractType.name, configNode.GetValue("name")); requirement = new InvalidContractRequirement(); valid = false; } else if (!requirementTypes.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '{0}', REQUIREMENT '{1}' of type '{2}': Unknown requirement '{3}'.", contractType.name, configNode.GetValue("name"), configNode.GetValue("type"), type); requirement = new InvalidContractRequirement(); valid = false; } else { // Create an instance of the ContractRequirement requirement = (ContractRequirement)Activator.CreateInstance(requirementTypes[type]); } // Set attributes requirement.contractType = contractType; requirement.dataNode = new DataNode(name, parent != null ? parent.dataNode : contractType.dataNode, requirement); // Load config valid &= requirement.LoadFromConfig(configNode); // Override the needsTitle if we have a parent node with hideChildren ContractRequirement parentRequirement = parent as ContractRequirement; if (parentRequirement != null) { if (parentRequirement.hideChildren) { requirement.hideChildren = true; requirement.needsTitle = false; } } // Check for unexpected values - always do this last if (requirement.GetType() != typeof(InvalidContractRequirement)) { valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, requirement); } // Load child nodes foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT")) { ContractRequirement child = null; valid &= ContractRequirement.GenerateRequirement(childNode, contractType, out child, requirement); if (child != null) { requirement.childNodes.Add(child); if (child.hasWarnings) { requirement.hasWarnings = true; } } } // Error for missing title if (requirement.needsTitle && string.IsNullOrEmpty(requirement.title)) { valid = contractType.minVersion < ContractConfigurator.ENHANCED_UI_VERSION; LoggingUtil.Log(contractType.minVersion >= ContractConfigurator.ENHANCED_UI_VERSION ? LoggingUtil.LogLevel.ERROR : LoggingUtil.LogLevel.WARNING, requirement, "{0}: missing required attribute 'title'.", requirement.ErrorPrefix(configNode)); } requirement.enabled = valid; requirement.log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; return(valid); }
public IEnumerable<ConfiguredContract> PendingContracts(ContractType type, Contract.ContractPrestige? prestige = null) { if (type == null) { return Enumerable.Empty<ConfiguredContract>(); } return contractDetails.SelectMany(p => p.Value.contracts).Union(priorityContracts). Where(c => c.contractType == type && (prestige == null || prestige == c.Prestige)); }
private IEnumerable <ConfiguredContract> GenerateContract(ContractType contractType) { // Set the desired prestige int t1, t2, t3; ContractSystem.GetContractCounts(Reputation.CurrentRep, 1000, out t1, out t2, out t3); if (contractType.prestige.Any()) { if (!contractType.prestige.Contains(Contract.ContractPrestige.Trivial)) { t1 = 0; } if (!contractType.prestige.Contains(Contract.ContractPrestige.Significant)) { t2 = 0; } if (!contractType.prestige.Contains(Contract.ContractPrestige.Exceptional)) { t3 = 0; } } int selection = rand.Next(0, t1 + t2 + t3); Contract.ContractPrestige prestige = selection < t1 ? Contract.ContractPrestige.Trivial : selection < (t1 + t2) ? Contract.ContractPrestige.Significant : Contract.ContractPrestige.Exceptional; // Generate the template ConfiguredContract templateContract = Contract.Generate(typeof(ConfiguredContract), prestige, rand.Next(), Contract.State.Withdrawn) as ConfiguredContract; // First, check the basic requirements if (!contractType.MeetBasicRequirements(templateContract)) { LoggingUtil.LogVerbose(this, "{0} was not generated: basic requirements not met.", contractType.name); if (++contractType.failedGenerationAttempts >= contractType.maxConsecutiveGenerationFailures) { contractType.lastGenerationFailure = Time.realtimeSinceStartup; } yield return(null); yield break; } // Try to refresh non-deterministic values before we check extended requirements OnInitializeValues.Fire(); LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel; LoggingUtil.LogLevel newLogLevel = contractType.trace ? LoggingUtil.LogLevel.VERBOSE : LoggingUtil.logLevel; try { // Set up for loop LoggingUtil.logLevel = newLogLevel; ConfiguredContract.currentContract = templateContract; // Set up the iterator to refresh non-deterministic values IEnumerable <string> iter = ConfigNodeUtil.UpdateNonDeterministicValuesIterator(contractType.dataNode); for (ContractGroup g = contractType.group; g != null; g = g.parent) { iter = ConfigNodeUtil.UpdateNonDeterministicValuesIterator(g.dataNode).Concat(iter); } // Update the actual values LoggingUtil.LogVerbose(this, "Refresh non-deterministic values for CONTRACT_TYPE = {0}", contractType.name); foreach (string val in iter) { lastKey = contractType.name + "[" + val + "]"; // Clear temp stuff LoggingUtil.logLevel = origLogLevel; ConfiguredContract.currentContract = null; if (val == null) { LoggingUtil.LogVerbose(this, "{0} was not generated: non-deterministic expression failure.", contractType.name); if (++contractType.failedGenerationAttempts >= contractType.maxConsecutiveGenerationFailures) { contractType.lastGenerationFailure = Time.realtimeSinceStartup; } OnInitializeFail.Fire(); yield return(null); yield break; } else { // Quick pause yield return(null); } // Re set up LoggingUtil.logLevel = newLogLevel; ConfiguredContract.currentContract = templateContract; } } finally { LoggingUtil.logLevel = origLogLevel; ConfiguredContract.currentContract = null; } // Store unique data foreach (string key in contractType.uniquenessChecks.Keys) { if (contractType.dataNode.GetType(key) == typeof(Vessel)) { Vessel v = contractType.dataNode[key] as Vessel; templateContract.uniqueData[key] = v != null ? (object)v.id : null; } else { templateContract.uniqueData[key] = contractType.dataNode[key]; } } templateContract.targetBody = contractType.targetBody; // Check the requirements for our selection if (contractType.MeetExtendedRequirements(templateContract, contractType) && templateContract.Initialize(contractType)) { templateContract.ContractState = Contract.State.Offered; yield return(templateContract); } // Failure, add a pause in before finishing else { LoggingUtil.LogVerbose(this, "{0} was not generated: requirement not met.", contractType.name); if (++contractType.failedGenerationAttempts >= contractType.maxConsecutiveGenerationFailures) { contractType.lastGenerationFailure = Time.realtimeSinceStartup; } OnInitializeFail.Fire(); yield return(null); } }
/// <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> /// Generates a ContractRequirement from a configuration node. /// </summary> /// <param name="configNode">ConfigNode to use in the generation.</param> /// <param name="contractType">ContractType that this requirement falls under</param> /// <param name="requirement">The ContractRequirement object.</param> /// <returns>Whether the load was successful</returns> public static bool GenerateRequirement(ConfigNode configNode, ContractType contractType, out ContractRequirement requirement, IContractConfiguratorFactory parent = null) { // Logging on LoggingUtil.CaptureLog = true; bool valid = true; // Get the type string type = configNode.GetValue("type"); string name = configNode.HasValue("name") ? configNode.GetValue("name") : type; if (string.IsNullOrEmpty(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "REQUIREMENT '" + configNode.GetValue("name") + "' does not specify the mandatory 'type' attribute."); requirement = new InvalidContractRequirement(); valid = false; } else if (!requirementTypes.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "REQUIREMENT '" + configNode.GetValue("name") + "' of type '" + configNode.GetValue("type") + "': " + "No ContractRequirement has been registered for type '" + type + "'."); requirement = new InvalidContractRequirement(); valid = false; } else { // Create an instance of the ContractRequirement requirement = (ContractRequirement)Activator.CreateInstance(requirementTypes[type]); } // Set attributes requirement.contractType = contractType; requirement.dataNode = new DataNode(name, parent != null ? parent.dataNode : contractType.dataNode, requirement); // Load config valid &= requirement.Load(configNode); // Check for unexpected values - always do this last if (requirement.GetType() != typeof(InvalidContractRequirement)) { valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, requirement); } // Load child nodes foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT")) { ContractRequirement child = null; valid &= ContractRequirement.GenerateRequirement(childNode, contractType, out child, requirement); if (child != null) { requirement.childNodes.Add(child); if (child.hasWarnings) { requirement.hasWarnings = true; } } } requirement.enabled = valid; requirement.log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; return(valid); }
/// <summary> /// 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 special values are not null if (contract.contractType == null) { foreach (KeyValuePair<string, bool> pair in dataValues) { // Only check if it is a required value if (pair.Value) { string name = pair.Key; if (!dataNode.IsInitialized(name)) { throw new ContractRequirementException("'" + name + "' was not initialized."); } object o = dataNode[name]; if (o == null) { throw new ContractRequirementException("'" + name + "' was null."); } else if (o == typeof(List<>)) { PropertyInfo prop = o.GetType().GetProperty("Count"); int count = (int)prop.GetValue(o, null); if (count == 0) { throw new ContractRequirementException("'" + name + "' had zero count."); } } else if (o == typeof(Vessel)) { Vessel v = (Vessel)o; if (v.state == Vessel.State.DEAD) { throw new ContractRequirementException("Vessel '" + v.vesselName + "' is dead."); } } } } } 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 = ContractSystem.Instance.Contracts.OfType<ConfiguredContract>(). 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)); } // Special case for pre-loader contracts if (contract.ContractState == Contract.State.Withdrawn) { contractList = contractList.Union(ContractPreLoader.Instance.PendingContracts(this, contract.Prestige). Where(c => c != null && c != contract && c.contractType != null)); } // Fileter 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, 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 : LoggingUtil.LogLevel.VERBOSE; string prefix = contract.contractType != null ? "Cancelling contract of type " + name + " (" + contract.Title + "): " : "Didn't generate contract 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; } }
private static void BehaviourGui(ContractType contractType, IEnumerable<BehaviourFactory> behaviourList, int indent) { foreach (BehaviourFactory behaviour in behaviourList) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(false)); GUILayout.Space(28); GUILayout.Label(new GUIContent(new string(' ', indent * 4) + behaviour, DebugInfo(behaviour)), behaviour.enabled ? behaviour.hasWarnings ? yellowLabel : GUI.skin.label : redLabel); if (contractType.enabled) { if (GUILayout.Button(behaviour.enabled ? check : cross, GUILayout.ExpandWidth(false))) { behaviour.enabled = !behaviour.enabled; } } GUILayout.EndHorizontal(); } }
/* * Generates a new BehaviourFactory from the given ConfigNode. */ public static BehaviourFactory GenerateBehaviourFactory(ConfigNode behaviourConfig, ContractType contractType) { // Get the type string type = behaviourConfig.GetValue("type"); if (!factories.ContainsKey(type)) { LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," + "BEHAVIOUR '" + behaviourConfig.GetValue("name") + "' of type '" + behaviourConfig.GetValue("type") + "': " + "No BehaviourFactory has been registered for type '" + type + "'."); return(null); } // Create an instance of the factory BehaviourFactory behaviourFactory = (BehaviourFactory)Activator.CreateInstance(factories[type]); // Set attributes behaviourFactory.contractType = contractType; behaviourFactory.targetBody = contractType.targetBody; // Load config bool valid = behaviourFactory.Load(behaviourConfig); // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(behaviourConfig, behaviourFactory); return(valid ? behaviourFactory : null); }
static GUIContent CurrencyGUIContent(Currency currency, ContractType contractType, double baseValue) { // Figure out the multiplier double multiplier = 1.0; if (GameVariables.Instance != null && contractType.targetBody != null) { multiplier *= GameVariables.Instance.GetContractDestinationWeight(contractType.targetBody); } string multInfo = baseValue.ToString("N0") + " (base) * " + multiplier.ToString("F1") + " (body)"; if (GameVariables.Instance != null && contractType.prestige.Count > 0) { double val = GameVariables.Instance.GetContractPrestigeFactor(contractType.prestige.First()); multiplier *= val; multInfo += " * " + val.ToString("F2") + " (prestige)"; } // Get the proper amount, add color double adjustedValue = multiplier * baseValue; string text = "<color=#"; switch (currency) { case Currency.Funds: text += "b4d455"; break; case Currency.Reputation: text += "e0d503"; break; case Currency.Science: text += "6dcff6"; break; } text += ">" + adjustedValue.ToString("N0") + "</color>"; // Return the gui content return new GUIContent(text, multInfo); }
private static void ParamGui(ContractType contractType, IEnumerable<ParameterFactory> paramList, int indent) { foreach (ParameterFactory param in paramList) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(false)); GUILayout.Space(28); GUILayout.Label(new GUIContent(new string(' ', indent * 4) + param, DebugInfo(param)), param.enabled ? param.hasWarnings ? yellowLabel : GUI.skin.label : redLabel); if (contractType.enabled) { if (GUILayout.Button(param.enabled ? check : cross, GUILayout.ExpandWidth(false))) { param.enabled = !param.enabled; } } GUILayout.EndHorizontal(); ParamGui(contractType, param.ChildParameters, indent + 1); RequirementGui(contractType, param.ChildRequirements, indent + 1); } }
private static void RequirementGui(ContractType contractType, IEnumerable<ContractRequirement> requirementList, int indent) { foreach (ContractRequirement requirement in requirementList) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(false)); GUILayout.Space(28); GUIStyle style = requirement.lastResult == null ? GUI.skin.label : requirement.lastResult.Value ? greenLabel : yellowLabel; GUILayout.Label(new GUIContent(new string(' ', indent * 4) + requirement, DebugInfo(requirement)), requirement.enabled ? requirement.hasWarnings ? yellowLabel : style : redLabel); if (contractType.enabled) { if (GUILayout.Button(requirement.enabled ? check : cross, GUILayout.ExpandWidth(false))) { requirement.enabled = !requirement.enabled; } } GUILayout.EndHorizontal(); RequirementGui(contractType, requirement.ChildRequirements, indent + 1); } }
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.GetType(), "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) { SetExpiry(); expiryType = DeadlineType.None; } else { SetExpiry(contractType.minExpiry, contractType.maxExpiry); } // 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.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(agent.Name, agent.GetMindsetString(), contractType.topic, contractType.subject, contractType.motivation, random.Next()); } else { description = contractType.description; } // Generate behaviours behaviours = new List<ContractBehaviour>(); if (!contractType.GenerateBehaviours(this)) { return false; } // Generate parameters if (!contractType.GenerateParameters(this)) { return false; } LoggingUtil.LogVerbose(this.GetType(), "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.name); return false; } finally { LoggingUtil.logLevel = origLogLevel; } }
/// <summary> /// Loads all the contact configuration nodes and creates ContractType objects. /// </summary> private IEnumerator <YieldInstruction> LoadContractConfig() { // Load all the contract groups LoggingUtil.LogDebug(this.GetType(), "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.GetType(), "Loading CONTRACT_GROUP: '" + name + "'"); ContractGroup contractGroup = null; try { contractGroup = new ContractGroup(name); } catch (ArgumentException) { LoggingUtil.LogError(this.GetType(), "Couldn't load CONTRACT_GROUP '" + name + "' due to a duplicate name."); } // Peform the actual load if (contractGroup != null) { bool success = false; try { 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); } } } } LoggingUtil.LogDebug(this.GetType(), "Loading CONTRACT_TYPE nodes."); ConfigNode[] contractConfigs = GameDatabase.Instance.GetConfigNodes("CONTRACT_TYPE"); totalContracts = contractConfigs.Count(); // First pass - create all the ContractType objects foreach (ConfigNode contractConfig in contractConfigs) { // Create the initial contract type LoggingUtil.LogVerbose(this.GetType(), "Pre-load for node: '" + contractConfig.GetValue("name") + "'"); try { ContractType contractType = new ContractType(contractConfig.GetValue("name")); } catch (ArgumentException) { LoggingUtil.LogError(this.GetType(), "Couldn't load CONTRACT_TYPE '" + contractConfig.GetValue("name") + "' due to a duplicate name."); } } // Second pass - do the actual loading of details foreach (ConfigNode contractConfig in contractConfigs) { attemptedContracts++; yield return(new WaitForEndOfFrame()); // Fetch the contractType string name = contractConfig.GetValue("name"); ContractType contractType = ContractType.GetContractType(name); if (contractType != null) { LoggingUtil.LogDebug(this.GetType(), "Loading CONTRACT_TYPE: '" + name + "'"); // Perform the load try { contractType.Load(contractConfig); if (contractType.enabled) { successContracts++; } } catch (Exception e) { Exception wrapper = new Exception("Error loading CONTRACT_TYPE '" + name + "'", e); LoggingUtil.LogException(wrapper); } } } LoggingUtil.LogInfo(this.GetType(), "Loaded " + successContracts + " out of " + totalContracts + " CONTRACT_TYPE nodes."); if (!reloading && LoggingUtil.logLevel == LoggingUtil.LogLevel.DEBUG || LoggingUtil.logLevel == LoggingUtil.LogLevel.VERBOSE) { ScreenMessages.PostScreenMessage("Contract Configurator: Loaded " + successContracts + " out of " + totalContracts + " contracts successfully.", 5, ScreenMessageStyle.UPPER_CENTER); } }
/// <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); }
/* * Loads all the contact configuration nodes and creates ContractType objects. */ void LoadContractConfig() { LoggingUtil.LogDebug(this.GetType(), "Loading CONTRACT_TYPE nodes."); ConfigNode[] contractConfigs = GameDatabase.Instance.GetConfigNodes("CONTRACT_TYPE"); // First pass - create all the ContractType objects foreach (ConfigNode contractConfig in contractConfigs) { totalContracts++; LoggingUtil.LogVerbose(this.GetType(), "Pre-load for node: '" + contractConfig.GetValue("name") + "'"); // Create the initial contract type try { ContractType contractType = new ContractType(contractConfig.GetValue("name")); } catch (ArgumentException) { LoggingUtil.LogError(this.GetType(), "Couldn't load CONTRACT_TYPE '" + contractConfig.GetValue("name") + "' due to a duplicate name."); // BUG: The same contract will get loaded twice, but just decrement the success counter so one shows as failed successContracts--; } } // Second pass - do the actual loading of details foreach (ConfigNode contractConfig in contractConfigs) { // Fetch the contractType string name = contractConfig.GetValue("name"); ContractType contractType = ContractType.contractTypes[name]; bool success = false; if (contractType != null) { LoggingUtil.LogDebug(this.GetType(), "Loading CONTRACT_TYPE: '" + name + "'"); // Perform the load try { if (contractType.Load(contractConfig)) { successContracts++; success = true; } } catch (Exception e) { Exception wrapper = new Exception("Error loading CONTRACT_TYPE '" + name + "'", e); Debug.LogException(wrapper); } finally { if (!success) { ContractType.contractTypes.Remove(name); } } } } LoggingUtil.LogInfo(this.GetType(), "Loaded " + successContracts + " out of " + totalContracts + " CONTRACT_TYPE nodes."); if (!reloading && LoggingUtil.logLevel == LoggingUtil.LogLevel.DEBUG || LoggingUtil.logLevel == LoggingUtil.LogLevel.VERBOSE) { ScreenMessages.PostScreenMessage("Contract Configurator: Loaded " + successContracts + " out of " + totalContracts + " contracts successfully.", 5, ScreenMessageStyle.UPPER_CENTER); } }