protected bool CheckContractGroup(ConfiguredContract contract, ContractGroup group) { if (group != null) { // Check the group is enabled if (!((ContractGroupParametersTemplate)HighLogic.CurrentGame.Parameters.CustomParams(SettingsBuilder.GroupParametersType)).IsEnabled(group.Root.name)) { throw new ContractRequirementException("Contract group " + group.name + " is not enabled."); } IEnumerable <ConfiguredContract> contractList = ConfiguredContract.CurrentContracts. Where(c => c.contractType != null && c != contract); // Check the group active limit int activeContracts = contractList.Count(c => c.contractType != null && group.BelongsToGroup(c.contractType)); if (group.maxSimultaneous != 0 && activeContracts >= group.maxSimultaneous) { throw new ContractRequirementException("Too many active contracts in group (" + group.name + ")."); } // Check the group completed limit if (group.maxCompletions != 0) { int finishedContracts = ConfiguredContract.CompletedContracts.Count(c => c.contractType != null && group.BelongsToGroup(c.contractType)); if (finishedContracts + activeContracts >= maxCompletions) { throw new ContractRequirementException("Too many completed contracts in group (" + group.name + ")."); } } return(CheckContractGroup(contract, group.parent)); } return(true); }
protected bool CheckContractGroup(ConfiguredContract contract, ContractGroup group) { if (group != null) { // Check the group active limit int activeContracts = ContractSystem.Instance.GetCurrentContracts <ConfiguredContract>().Count(c => c.contractType != null && group.BelongsToGroup(c.contractType)); if (contract.ContractState == Contract.State.Offered || contract.ContractState == Contract.State.Active) { activeContracts--; } if (group.maxSimultaneous != 0 && activeContracts >= group.maxSimultaneous) { LoggingUtil.LogVerbose(this, "Didn't generate contract type " + name + ", too many active contracts in group."); return(false); } // Check the group completed limit if (group.maxCompletions != 0) { int finishedContracts = ContractSystem.Instance.GetCompletedContracts <ConfiguredContract>().Count(c => c.contractType != null && group.BelongsToGroup(c.contractType)); if (finishedContracts + activeContracts >= maxCompletions) { LoggingUtil.LogVerbose(this, "Didn't generate contract type " + name + ", too many completed contracts in group."); return(false); } } return(CheckContractGroup(contract, group.parent)); } return(true); }
private IEnumerable <ConfiguredContract> ContractEnumerator() { // Loop through all the contract groups IEnumerable <ContractGroup> groups = ContractGroup.AllGroups; for (int i = 0; i < groups.Count(); i++) { nextContractGroup = (nextContractGroup + 1) % groups.Count(); ContractGroup group = groups.ElementAt(nextContractGroup); List <ContractType> contractTypes = ContractType.AllValidContractTypes.ToList(); contractTypes.Shuffle(); foreach (ContractType ct in contractTypes) { // Is the contract time part of this group, and is it allowed to attempt to generate if (ct.group == group && ct.lastGenerationFailure + FAILURE_WAIT_TIME < Time.realtimeSinceStartup) { if (ct.lastGenerationFailure != -100) { ct.lastGenerationFailure = -100; ct.failedGenerationAttempts = 0; } // Are we in the right scene, or is is a special contract that can generate in any scene if (HighLogic.LoadedScene == GameScenes.SPACECENTER || ct.autoAccept) { foreach (ConfiguredContract contract in GenerateContract(ct)) { yield return(contract); } } } } } }
/// <summary> /// Static method (used by other mods via reflection) to get the group name. /// </summary> public static string contractGroupName(Contract c) { if (c == null || c.GetType() != typeof(ConfiguredContract)) { return(""); } ConfiguredContract cc = (ConfiguredContract)c; if (cc.contractType == null) { return(""); } ContractGroup group = cc.contractType.group; if (group == null) { return(""); } while (group.parent != null) { group = group.parent; } return(group.name); }
public ContractType(string name) { this.name = name; contractTypes.Add(name, this); // Member defaults group = null; agent = null; minExpiry = 0; maxExpiry = 0; deadline = 0; cancellable = true; declinable = true; autoAccept = false; prestige = new List <Contract.ContractPrestige>(); maxCompletions = 0; maxSimultaneous = 0; rewardScience = 0.0f; rewardReputation = 0.0f; rewardFunds = 0.0f; failureReputation = 0.0f; failureFunds = 0.0f; advanceFunds = 0.0f; enabled = true; }
public override void OnLoad(ConfigNode node) { try { lastMCButton = ConfigNodeUtil.ParseValue <MissionControlButton>(node, "lastMCButton", MissionControlButton.All); DisplayOfferedOrbits = ConfigNodeUtil.ParseValue <bool?>(node, "DisplayOfferedOrbits", (bool?)ContractDefs.DisplayOfferedOrbits).Value; DisplayOfferedWaypoints = ConfigNodeUtil.ParseValue <bool?>(node, "DisplayOfferedWaypoints", (bool?)ContractDefs.DisplayOfferedWaypoints).Value; DisplayActiveOrbits = ConfigNodeUtil.ParseValue <bool?>(node, "DisplayActiveOrbits", (bool?)true).Value; DisplayActiveWaypoints = ConfigNodeUtil.ParseValue <bool?>(node, "DisplayActiveWaypoints", (bool?)true).Value; foreach (ConfigNode groupNode in node.GetNodes("CONTRACT_GROUP")) { string groupName = groupNode.GetValue("group"); if (ContractGroup.contractGroups.ContainsKey(groupName)) { ContractGroup group = ContractGroup.contractGroups[groupName]; ContractGroupDetails details = new ContractGroupDetails(group); details.enabled = ConfigNodeUtil.ParseValue <bool>(groupNode, "enabled"); contractGroupDetails[group.name] = details; } else { LoggingUtil.LogWarning(this, "Couldn't find contract group with name '" + groupName + "'"); } } foreach (ConfigNode stateNode in node.GetNodes("CONTRACT_STATE")) { string typeName = stateNode.GetValue("type"); if (!string.IsNullOrEmpty(typeName)) { Type contractType = null; try { contractType = ConfigNodeUtil.ParseTypeValue(typeName); StockContractDetails details = new StockContractDetails(contractType); details.enabled = ConfigNodeUtil.ParseValue <bool>(stateNode, "enabled"); stockContractDetails[contractType] = details; ContractDisabler.SetContractState(contractType, details.enabled); } catch (ArgumentException) { LoggingUtil.LogWarning(this, "Couldn't find contract type with name '" + typeName + "'"); } } } } catch (Exception e) { LoggingUtil.LogError(this, "Error loading ContractConfiguratorSettings from persistance file!"); LoggingUtil.LogException(e); ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "ContractConfiguratorSettings"); } }
public static bool IsEnabled(ContractGroup group) { string identifier = group == null ? "" : group.name; if (Instance != null && Instance.contractGroupDetails.ContainsKey(identifier)) { return Instance.contractGroupDetails[identifier].enabled; } return true; }
public static bool IsEnabled(ContractGroup group) { string identifier = group == null ? "" : group.name; if (Instance != null && Instance.contractGroupDetails.ContainsKey(identifier)) { return(Instance.contractGroupDetails[identifier].enabled); } return(true); }
/// <summary> /// Loads all the contact configuration group nodes. /// </summary> private IEnumerator <YieldInstruction> LoadGroupConfig() { // Load all the contract groups LoggingUtil.LogDebug(this, "Loading CONTRACT_GROUP nodes."); ConfigNode[] contractGroups = GameDatabase.Instance.GetConfigNodes("CONTRACT_GROUP"); foreach (ConfigNode groupConfig in contractGroups) { // Create the group string name = groupConfig.GetValue("name"); LoggingUtil.LogInfo(this, "Loading CONTRACT_GROUP: '" + name + "'"); ContractGroup contractGroup = null; try { contractGroup = new ContractGroup(name); } catch (ArgumentException) { LoggingUtil.LogError(this, "Couldn't load CONTRACT_GROUP '" + name + "' due to a duplicate name."); } // Peform the actual load if (contractGroup != null) { bool success = false; try { ConfigNodeUtil.ClearCache(true); success = contractGroup.Load(groupConfig); } catch (Exception e) { Exception wrapper = new Exception("Error loading CONTRACT_GROUP '" + name + "'", e); LoggingUtil.LogException(wrapper); } finally { if (!success) { ContractGroup.contractGroups.Remove(name); } } } } if (!reloading) { yield return(new WaitForEndOfFrame()); } // Emit settings for the menu SettingsBuilder.EmitSettings(); yield break; }
protected IEnumerable<ContractGroup> ChildGroups(ContractGroup group) { foreach (ContractGroup child in ContractGroup.AllGroups.Where(g => g != null && g.parent == group)) { yield return child; foreach (ContractGroup descendent in ChildGroups(child)) { yield return descendent; } } }
/// <summary> /// Static method (used by other mods via reflection) to get the contract group display name. /// </summary> public static string GroupDisplayName(string groupName) { if (string.IsNullOrEmpty(groupName)) { return(""); } ContractGroup group = contractGroups.ContainsKey(groupName) ? contractGroups[groupName] : null; return(group == null ? "" : group.displayName); }
private void ContractGroupLine(ContractGroup contractGroup, int indent = 0) { string identifier = contractGroup == null ? "" : contractGroup.name; if (!contractGroupDetails.ContainsKey(identifier)) { contractGroupDetails[identifier] = new ContractGroupDetails(contractGroup); } ContractGroupDetails details = contractGroupDetails[identifier]; GUILayout.BeginHorizontal(); GUILayout.Label("", contractRegularText, GUILayout.ExpandWidth(false), GUILayout.Width((indent + 1) * 16)); string groupName = contractGroup == null ? "No Group" : contractGroup.displayName; GUILayout.Label(groupName, details.enabled ? contractRegularText : contractDisabledText, GUILayout.ExpandWidth(true)); if (contractGroup != null && contractGroup.parent == null) { bool enabled = GUILayout.Toggle(details.enabled, new GUIContent("", "Click to " + (details.enabled ? "disable " : "enable ") + contractGroup.displayName + " contracts."), contractToggleStyle, GUILayout.ExpandWidth(false)); if (enabled != details.enabled) { details.enabled = enabled; if (enabled) { foreach (KeyValuePair <Type, StockContractDetails> pair in stockContractDetails. Where(p => ContractDisabler.DisablingGroups(p.Key).Contains(contractGroup))) { pair.Value.enabled = false; ContractDisabler.SetContractState(pair.Key, false); } } else { foreach (KeyValuePair <Type, StockContractDetails> pair in stockContractDetails. Where(p => ContractDisabler.DisablingGroups(p.Key).Contains(contractGroup) && ContractDisabler.DisablingGroups(p.Key).All(g => !IsEnabled(g)))) { pair.Value.enabled = true; ContractDisabler.SetContractState(pair.Key, true); } } } } GUILayout.EndHorizontal(); }
public static void SetContractToDisabled(string contract, ContractGroup group) { Type contractType = contractTypes.Where(t => t.Name == contract).FirstOrDefault(); if (contractType == null) { LoggingUtil.LogWarning(typeof(ContractDisabler), "Couldn't find ContractType '" + contract + "' to disable."); } if (!contractDetails.ContainsKey(contractType)) { contractDetails[contractType] = new ContractDetails(contractType); } ContractDetails details = contractDetails[contractType]; details.disablingGroups.AddUnique(group); SetContractState(contractType, false); }
/// <summary> /// 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 the contract group details from the given config node. /// </summary> /// <param name="configNode">The config node to load from</param> /// <returns>Whether we were successful.</returns> public bool Load(ConfigNode configNode) { try { dataNode = new DataNode(configNode.GetValue("name"), this); LoggingUtil.CaptureLog = true; ConfigNodeUtil.SetCurrentDataNode(dataNode); bool valid = true; valid &= ConfigNodeUtil.ParseValue<string>(configNode, "name", x => name = x, this); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "displayName", x => displayName = x, this, name); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "minVersion", x => minVersion = x, this, ""); valid &= ConfigNodeUtil.ParseValue<int>(configNode, "maxCompletions", x => maxCompletions = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue<int>(configNode, "maxSimultaneous", x => maxSimultaneous = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue<List<string>>(configNode, "disabledContractType", x => disabledContractType = x, this, new List<string>()); if (!string.IsNullOrEmpty(minVersion)) { if (Util.Version.VerifyAssemblyVersion("ContractConfigurator", minVersion) == null) { valid = false; var ainfoV = Attribute.GetCustomAttribute(typeof(ExceptionLogWindow).Assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute; string title = "Contract Configurator " + ainfoV.InformationalVersion + " Message"; string message = "The contract group '" + name + "' requires at least Contract Configurator " + minVersion + " to work, and you are running version " + ainfoV.InformationalVersion + ". Please upgrade Contract Configurator to use the contracts in this group."; DialogOption dialogOption = new DialogOption("Okay", new Callback(DoNothing), true); PopupDialog.SpawnPopupDialog(new MultiOptionDialog(message, title, HighLogic.Skin, dialogOption), false, HighLogic.Skin); } } // Load DATA nodes valid &= dataNode.ParseDataNodes(configNode, this, dataValues, uniquenessChecks); // Do the deferred loads valid &= ConfigNodeUtil.ExecuteDeferredLoads(); config = configNode.ToString(); log += LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; // Load child groups foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "CONTRACT_GROUP")) { ContractGroup child = null; string childName = childNode.GetValue("name"); try { child = new ContractGroup(childName); } catch (ArgumentException) { LoggingUtil.LogError(this, "Couldn't load CONTRACT_GROUP '" + childName + "' due to a duplicate name."); valid = false; continue; } valid &= child.Load(childNode); child.parent = this; child.dataNode.Parent = dataNode; if (child.hasWarnings) { hasWarnings = true; } } // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, this); // Invalidate children if (!valid) { Invalidate(); } enabled = valid; return valid; } catch { enabled = false; throw; } }
/// <summary> /// Loads the contract group details from the given config node. /// </summary> /// <param name="configNode">The config node to load from</param> /// <returns>Whether we were successful.</returns> public bool Load(ConfigNode configNode) { try { dataNode = new DataNode(configNode.GetValue("name"), this); LoggingUtil.CaptureLog = true; ConfigNodeUtil.SetCurrentDataNode(dataNode); bool valid = true; valid &= ConfigNodeUtil.ParseValue <string>(configNode, "name", x => name = x, this); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "displayName", x => displayName = x, this, name); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "minVersion", x => minVersionStr = x, this, ""); valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxCompletions", x => maxCompletions = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxSimultaneous", x => maxSimultaneous = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue <List <string> >(configNode, "disabledContractType", x => disabledContractType = x, this, new List <string>()); valid &= ConfigNodeUtil.ParseValue <Agent>(configNode, "agent", x => agent = x, this, (Agent)null); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "sortKey", x => sortKey = x, this, displayName); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "tip", x => {}, this, ""); if (configNode.HasValue("sortKey") && parent == null) { sortKey = displayName; LoggingUtil.LogWarning(this, ErrorPrefix() + ": Using the sortKey field is only applicable on child CONTRACT_GROUP elements"); } if (!string.IsNullOrEmpty(minVersionStr)) { if (Util.Version.VerifyAssemblyVersion("ContractConfigurator", minVersionStr) == null) { valid = false; var ainfoV = Attribute.GetCustomAttribute(typeof(ExceptionLogWindow).Assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute; string title = "Contract Configurator " + ainfoV.InformationalVersion + " Message"; string message = "The contract group '" + name + "' requires at least Contract Configurator " + minVersionStr + " to work, and you are running version " + ainfoV.InformationalVersion + ". Please upgrade Contract Configurator to use the contracts in this group."; DialogGUIButton dialogOption = new DialogGUIButton("Okay", new Callback(DoNothing), true); PopupDialog.SpawnPopupDialog(new MultiOptionDialog(message, title, UISkinManager.GetSkin("default"), dialogOption), false, UISkinManager.GetSkin("default")); } } // Load DATA nodes valid &= dataNode.ParseDataNodes(configNode, this, dataValues, uniquenessChecks); // Do the deferred loads valid &= ConfigNodeUtil.ExecuteDeferredLoads(); // Do post-deferred load warnings if (agent == null) { LoggingUtil.LogWarning(this, ErrorPrefix() + ": Providing the agent field for all CONTRACT_GROUP nodes is highly recommended, as the agent is used to group contracts in Mission Control."); } if (string.IsNullOrEmpty(minVersionStr) || minVersion < ContractConfigurator.ENHANCED_UI_VERSION) { LoggingUtil.LogWarning(this, ErrorPrefix() + ": No minVersion or older minVersion provided. It is recommended that the minVersion is set to at least 1.15.0 to turn important warnings for deprecated functionality into errors."); } if (!configNode.HasValue("displayName")) { LoggingUtil.LogWarning(this, ErrorPrefix() + ": No display name provided. A display name is recommended, as it is used in the Mission Control UI."); } config = configNode.ToString(); log += LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; // Load child groups foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "CONTRACT_GROUP")) { ContractGroup child = null; string childName = childNode.GetValue("name"); try { child = new ContractGroup(childName); } catch (ArgumentException) { LoggingUtil.LogError(this, "Couldn't load CONTRACT_GROUP '" + childName + "' due to a duplicate name."); valid = false; continue; } child.parent = this; valid &= child.Load(childNode); child.dataNode.Parent = dataNode; if (child.hasWarnings) { hasWarnings = true; } } // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, this); // Invalidate children if (!valid) { Invalidate(); } enabled = valid; return(valid); } catch { enabled = false; throw; } }
/// <summary> /// Loads the contract type details from the given config node. /// </summary> /// <param name="configNode">The config node to load from.</param> /// <returns>Whether the load was successful.</returns> public bool Load(ConfigNode configNode) { try { // Logging on LoggingUtil.CaptureLog = true; dataNode = new DataNode(configNode.GetValue("name"), this); ConfigNodeUtil.ClearCache(true); ConfigNodeUtil.SetCurrentDataNode(dataNode); bool valid = true; valid &= ConfigNodeUtil.ParseValue <string>(configNode, "name", x => name = x, this); // Load contract text details valid &= ConfigNodeUtil.ParseValue <ContractGroup>(configNode, "group", x => group = x, this, (ContractGroup)null); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "title", x => title = x, this); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "tag", x => tag = x, this, ""); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "description", x => description = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "topic", x => topic = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "subject", x => subject = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "motivation", x => motivation = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "notes", x => notes = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "synopsis", x => synopsis = x, this); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "completedMessage", x => completedMessage = x, this); // Load optional attributes valid &= ConfigNodeUtil.ParseValue <Agent>(configNode, "agent", x => agent = x, this, (Agent)null); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "minExpiry", x => minExpiry = x, this, 1.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "maxExpiry", x => maxExpiry = x, this, 7.0f, x => Validation.GE(x, minExpiry)); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "deadline", x => deadline = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue <bool>(configNode, "cancellable", x => cancellable = x, this, true); valid &= ConfigNodeUtil.ParseValue <bool>(configNode, "declinable", x => declinable = x, this, true); valid &= ConfigNodeUtil.ParseValue <List <Contract.ContractPrestige> >(configNode, "prestige", x => prestige = x, this, new List <Contract.ContractPrestige>()); valid &= ConfigNodeUtil.ParseValue <CelestialBody>(configNode, "targetBody", x => targetBody = x, this, (CelestialBody)null); valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxCompletions", x => maxCompletions = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxSimultaneous", x => maxSimultaneous = x, this, 0, x => Validation.GE(x, 0)); // Load rewards valid &= ConfigNodeUtil.ParseValue <float>(configNode, "rewardFunds", x => rewardFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "rewardReputation", x => rewardReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "rewardScience", x => rewardScience = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "failureFunds", x => failureFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "failureReputation", x => failureReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue <float>(configNode, "advanceFunds", x => advanceFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f)); // Load other values valid &= ConfigNodeUtil.ParseValue <double>(configNode, "weight", x => weight = x, this, 1.0, x => Validation.GE(x, 0.0f)); // TODO - these are to be deprecated if (configNode.HasValue("targetBodies")) { valid &= ConfigNodeUtil.ParseValue <List <CelestialBody> >(configNode, "targetBodies", x => targetBodies = x, this, new List <CelestialBody>()); LoggingUtil.LogWarning(this, "The 'targetBodies' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } if (configNode.HasValue("targetVessel")) { valid &= ConfigNodeUtil.ParseValue <Vessel>(configNode, "targetVessel", x => targetVessel = x, this, (Vessel)null); LoggingUtil.LogWarning(this, "The 'targetVessel' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } if (configNode.HasValue("targetVessels")) { valid &= ConfigNodeUtil.ParseValue <List <Vessel> >(configNode, "targetVessels", x => targetVessels = x, this, new List <Vessel>()); LoggingUtil.LogWarning(this, "The 'targetVessels' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } if (configNode.HasValue("targetKerbal")) { valid &= ConfigNodeUtil.ParseValue <Kerbal>(configNode, "targetKerbal", x => targetKerbal = x, this, (Kerbal)null); LoggingUtil.LogWarning(this, "The 'targetKerbal' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } if (configNode.HasValue("targetKerbals")) { valid &= ConfigNodeUtil.ParseValue <List <Kerbal> >(configNode, "targetKerbals", x => targetKerbals = x, this, new List <Kerbal>()); LoggingUtil.LogWarning(this, "The 'targetKerbals' attribute is obsolete as of Contract Configurator 0.7.4. It will be removed in 1.0.0 in favour of the DATA { } node."); } // Load DATA nodes foreach (ConfigNode data in ConfigNodeUtil.GetChildNodes(configNode, "DATA")) { Type type = null; bool requiredValue = true; valid &= ConfigNodeUtil.ParseValue <Type>(data, "type", x => type = x, this); valid &= ConfigNodeUtil.ParseValue <bool>(data, "requiredValue", x => requiredValue = x, this, true); if (type != null) { foreach (ConfigNode.Value pair in data.values) { string name = pair.name; if (name != "type" && name != "requiredValue") { object value = null; // Create the setter function Type actionType = typeof(Action <>).MakeGenericType(type); Delegate del = Delegate.CreateDelegate(actionType, value, typeof(ContractType).GetMethod("NullAction")); // Get the ParseValue method MethodInfo method = typeof(ConfigNodeUtil).GetMethods(BindingFlags.Static | BindingFlags.Public). Where(m => m.Name == "ParseValue" && m.GetParameters().Count() == 4).Single(); method = method.MakeGenericMethod(new Type[] { type }); // Invoke the ParseValue method valid &= (bool)method.Invoke(null, new object[] { data, name, del, this }); dataValues[name] = requiredValue; } } } } // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, this); log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; // Load parameters foreach (ConfigNode contractParameter in ConfigNodeUtil.GetChildNodes(configNode, "PARAMETER")) { ParameterFactory paramFactory = null; valid &= ParameterFactory.GenerateParameterFactory(contractParameter, this, out paramFactory); if (paramFactory != null) { paramFactories.Add(paramFactory); if (paramFactory.hasWarnings) { hasWarnings = true; } } } // Load behaviours foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "BEHAVIOUR")) { BehaviourFactory behaviourFactory = null; valid &= BehaviourFactory.GenerateBehaviourFactory(requirementNode, this, out behaviourFactory); if (behaviourFactory != null) { behaviourFactories.Add(behaviourFactory); if (behaviourFactory.hasWarnings) { hasWarnings = true; } } } // Load requirements foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT")) { ContractRequirement requirement = null; valid &= ContractRequirement.GenerateRequirement(requirementNode, this, out requirement); if (requirement != null) { requirements.Add(requirement); if (requirement.hasWarnings) { hasWarnings = true; } } } // Logging on LoggingUtil.CaptureLog = true; // Check we have at least one valid parameter if (paramFactories.Count() == 0) { LoggingUtil.LogError(this.GetType(), ErrorPrefix() + ": Need at least one parameter for a contract!"); valid = false; } // Do the deferred loads valid &= ConfigNodeUtil.ExecuteDeferredLoads(); config = configNode.ToString(); hash = config.GetHashCode(); enabled = valid; log += LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; return(valid); } catch { enabled = false; throw; } }
/// <summary> /// Loads the contract type details from the given config node. /// </summary> /// <param name="configNode">The config node to load from.</param> /// <returns>Whether the load was successful.</returns> public bool Load(ConfigNode configNode) { LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel; try { // Logging on LoggingUtil.CaptureLog = true; ConfigNodeUtil.SetCurrentDataNode(null); // Load values that are immediately required bool valid = true; valid &= ConfigNodeUtil.ParseValue<ContractGroup>(configNode, "group", x => group = x, this, (ContractGroup)null); // Set up the data node dataNode = new DataNode(configNode.GetValue("name"), group != null ? group.dataNode : null, this); ConfigNodeUtil.SetCurrentDataNode(dataNode); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "name", x => name = x, this); // Try to turn on trace mode valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "trace", x => trace = x, this, false); if (trace) { LoggingUtil.logLevel = LoggingUtil.LogLevel.VERBOSE; LoggingUtil.LogWarning(this, "Tracing enabled for contract type " + name); } // Load contract text details valid &= ConfigNodeUtil.ParseValue<string>(configNode, "title", x => title = x, this); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "tag", x => tag = x, this, ""); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "description", x => description = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "topic", x => topic = x, this, ""); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "subject", x => subject = x, this, ""); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "motivation", x => motivation = x, this, ""); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "notes", x => notes = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "synopsis", x => synopsis = x, this); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "completedMessage", x => completedMessage = x, this); // Load optional attributes valid &= ConfigNodeUtil.ParseValue<Agent>(configNode, "agent", x => agent = x, this, (Agent)null); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "minExpiry", x => minExpiry = x, this, 1.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "maxExpiry", x => maxExpiry = x, this, 7.0f, x => Validation.GE(x, minExpiry)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "deadline", x => deadline = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "cancellable", x => cancellable = x, this, true); valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "declinable", x => declinable = x, this, true); valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "autoAccept", x => autoAccept = x, this, false); valid &= ConfigNodeUtil.ParseValue<List<Contract.ContractPrestige>>(configNode, "prestige", x => prestige = x, this, new List<Contract.ContractPrestige>()); valid &= ConfigNodeUtil.ParseValue<CelestialBody>(configNode, "targetBody", x => targetBody = x, this, (CelestialBody)null); valid &= ConfigNodeUtil.ParseValue<int>(configNode, "maxCompletions", x => maxCompletions = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue<int>(configNode, "maxSimultaneous", x => maxSimultaneous = x, this, 0, x => Validation.GE(x, 0)); // Load rewards valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardFunds", x => rewardFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardReputation", x => rewardReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardScience", x => rewardScience = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "failureFunds", x => failureFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "failureReputation", x => failureReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "advanceFunds", x => advanceFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f)); // Load other values valid &= ConfigNodeUtil.ParseValue<double>(configNode, "weight", x => weight = x, this, 1.0, x => Validation.GE(x, 0.0f)); // Merge in data from the parent contract group for (ContractGroup currentGroup = group; currentGroup != null; currentGroup = currentGroup.parent) { // Merge dataValues - this is a flag saying what values need to be unique at the contract level foreach (KeyValuePair<string, bool> pair in currentGroup.dataValues) { dataValues[group.name + ":" + pair.Key] = pair.Value; } // Merge uniquenessChecks foreach (KeyValuePair<string, DataNode.UniquenessCheck> pair in currentGroup.uniquenessChecks) { uniquenessChecks[group.name + ":" + pair.Key] = pair.Value; } } // Load DATA nodes valid &= dataNode.ParseDataNodes(configNode, this, dataValues, uniquenessChecks); // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, this); log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; // Load parameters foreach (ConfigNode contractParameter in ConfigNodeUtil.GetChildNodes(configNode, "PARAMETER")) { ParameterFactory paramFactory = null; valid &= ParameterFactory.GenerateParameterFactory(contractParameter, this, out paramFactory); if (paramFactory != null) { paramFactories.Add(paramFactory); if (paramFactory.hasWarnings) { hasWarnings = true; } } } // Load behaviours foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "BEHAVIOUR")) { BehaviourFactory behaviourFactory = null; valid &= BehaviourFactory.GenerateBehaviourFactory(requirementNode, this, out behaviourFactory); if (behaviourFactory != null) { behaviourFactories.Add(behaviourFactory); if (behaviourFactory.hasWarnings) { hasWarnings = true; } } } // Load requirements foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT")) { ContractRequirement requirement = null; valid &= ContractRequirement.GenerateRequirement(requirementNode, this, out requirement); if (requirement != null) { requirements.Add(requirement); if (requirement.hasWarnings) { hasWarnings = true; } } } // Logging on LoggingUtil.CaptureLog = true; // Check we have at least one valid parameter if (paramFactories.Count() == 0) { LoggingUtil.LogError(this.GetType(), ErrorPrefix() + ": Need at least one parameter for a contract!"); valid = false; } // Do the deferred loads valid &= ConfigNodeUtil.ExecuteDeferredLoads(); config = configNode.ToString(); hash = config.GetHashCode(); enabled = valid; log += LoggingUtil.capturedLog; if (LoggingUtil.logLevel == LoggingUtil.LogLevel.VERBOSE || LoggingUtil.logLevel == LoggingUtil.LogLevel.DEBUG) { //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // to write the complete config and log for contract to both the system log and // a seperate CC log file // string pattern = @"\[(VERBOSE|DEBUG|INFO|WARNING|ERROR)\] ContractConfigurator\.ExpressionParser.BaseParser.+\n"; string replacement = ""; Regex rgx = new Regex(pattern); // First, write to the standard log file. the regex strips out the leading text of the line, but // if you want the text there, then just remove the rgx.Replace LoggingUtil.LogDebug(this, config); // Write the log out, ignoring the BaseParser lines LoggingUtil.LogDebug(this, rgx.Replace(log, replacement)); // Now write to the CC log file, in a much cleaner manner string path = ccLogFile; // Delete the file first time through, ignore any errors if (deleteCCLogfile) { deleteCCLogfile = false; try { if (File.Exists(path)) File.Delete(path); } catch { LoggingUtil.LogError(this, "Exception while attempting to delete the file: " + path); } } // Create the file if it doesn't exist if (!File.Exists(path)) { // Create a file to write to. try { using (StreamWriter sw = File.CreateText(path)) {} } catch { LoggingUtil.LogError(this, "Exception while attempting to create the file: " + path); } } // This regex also strips out the second part of the line, so that the output is very clean string pattern2 = @"\[(VERBOSE|DEBUG|INFO|WARNING|ERROR)\] ContractConfigurator\.ExpressionParser\.DataNode: "; Regex rgx2 = new Regex(pattern2); // Now write the config and the cleaned up log to it try { using (StreamWriter sw = File.AppendText (path)) { sw.WriteLine (config); sw.WriteLine("++++++++++\n"); sw.WriteLine(rgx2.Replace(rgx.Replace(log, replacement), replacement)); sw.WriteLine("=================================================================================="); } } catch { LoggingUtil.LogError(this, "Exception while attempting to write to the file: " + path); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ } LoggingUtil.CaptureLog = false; return valid; } catch { enabled = false; throw; } finally { LoggingUtil.logLevel = origLogLevel; loaded = true; } }
/// <summary> /// Loads the contract group details from the given config node. /// </summary> /// <param name="configNode">The config node to load from</param> /// <returns>Whether we were successful.</returns> public bool Load(ConfigNode configNode) { try { dataNode = new DataNode(configNode.GetValue("name"), this); LoggingUtil.CaptureLog = true; ConfigNodeUtil.ClearCache(true); ConfigNodeUtil.SetCurrentDataNode(dataNode); bool valid = true; valid &= ConfigNodeUtil.ParseValue <string>(configNode, "name", x => name = x, this); valid &= ConfigNodeUtil.ParseValue <string>(configNode, "minVersion", x => minVersion = x, this, ""); valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxCompletions", x => maxCompletions = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxSimultaneous", x => maxSimultaneous = x, this, 0, x => Validation.GE(x, 0)); if (!string.IsNullOrEmpty(minVersion)) { if (Util.Version.VerifyAssemblyVersion("ContractConfigurator", minVersion) == null) { valid = false; var ainfoV = Attribute.GetCustomAttribute(typeof(ExceptionLogWindow).Assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute; string title = "Contract Configurator " + ainfoV.InformationalVersion + " Message"; string message = "The contract group '" + name + "' requires at least Contract Configurator " + minVersion + " to work, and you are running version " + ainfoV.InformationalVersion + ". Please upgrade Contract Configurator to use the contracts in this group."; DialogOption dialogOption = new DialogOption("Okay", new Callback(DoNothing), true); PopupDialog.SpawnPopupDialog(new MultiOptionDialog(message, title, HighLogic.Skin, dialogOption), false, HighLogic.Skin); } } // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, this); // Do the deferred loads valid &= ConfigNodeUtil.ExecuteDeferredLoads(); config = configNode.ToString(); log += LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; // Load child groups foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "CONTRACT_GROUP")) { ContractGroup child = null; string name = childNode.GetValue("name"); try { child = new ContractGroup(name); } catch (ArgumentException) { LoggingUtil.LogError(this, "Couldn't load CONTRACT_GROUP '" + name + "' due to a duplicate name."); valid = false; continue; } valid &= child.Load(childNode); child.parent = this; if (child.hasWarnings) { hasWarnings = true; } } // Invalidate children if (!valid) { Invalidate(); } enabled = valid; return(valid); } catch { enabled = false; throw; } }
/// <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); } }
private static void GroupGui(ContractGroup contractGroup, int indent) { if (contractGroup != null) { GUILayout.BeginHorizontal(); if (indent != 0) { GUILayout.Label("", GUILayout.ExpandWidth(false), GUILayout.Width(indent * 16)); } if (GUILayout.Button(contractGroup.expandInDebug ? "-" : "+", GUILayout.Width(20), GUILayout.Height(20))) { contractGroup.expandInDebug = !contractGroup.expandInDebug; } GUIStyle style = greenLabel; if (!contractGroup.enabled) { style = redLabel; } else { if (contractGroup.hasWarnings) { style = yellowLabel; } foreach (ContractType contractType in guiContracts.Where(ct => contractGroup == null ? ct.group == null : contractGroup.BelongsToGroup(ct))) { if (!contractType.enabled) { style = redLabel; break; } else if (contractType.hasWarnings) { style = yellowLabel; } } } GUILayout.Label(new GUIContent(contractGroup.ToString(), DebugInfo(contractGroup)), style); GUILayout.EndHorizontal(); } if (contractGroup == null || contractGroup.expandInDebug) { // Child groups if (contractGroup != null) { foreach (ContractGroup childGroup in ContractGroup.AllGroups.Where(g => g != null && g.parent != null && g.parent.name == contractGroup.name)) { GroupGui(childGroup, indent + 1); } } // Child contract types foreach (ContractType contractType in guiContracts.Where(ct => ct.group == contractGroup)) { GUILayout.BeginHorizontal(); if (contractGroup != null) { GUILayout.Label("", GUILayout.ExpandWidth(false), GUILayout.Width((indent+1) * 16)); } if (GUILayout.Button(contractType.expandInDebug ? "-" : "+", GUILayout.Width(20), GUILayout.Height(20))) { contractType.expandInDebug = !contractType.expandInDebug; } GUILayout.Label(new GUIContent(contractType.ToString(), DebugInfo(contractType)), contractType.enabled ? contractType.hasWarnings ? yellowLabel : GUI.skin.label : redLabel); GUILayout.EndHorizontal(); if (contractType.expandInDebug) { // Output children ParamGui(contractType, contractType.ParamFactories, indent + (contractGroup == null ? 1 : 2)); RequirementGui(contractType, contractType.Requirements, indent + (contractGroup == null ? 1 : 2)); BehaviourGui(contractType, contractType.BehaviourFactories, indent + (contractGroup == null ? 1 : 2)); GUILayout.Space(8); } } } }
private IEnumerable<ConfiguredContract> ContractGenerator(Contract.ContractPrestige prestige, ContractGroup group) { ConfiguredContract templateContract = Contract.Generate(typeof(ConfiguredContract), prestige, rand.Next(), Contract.State.Withdrawn) as ConfiguredContract; // 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)) { // Check if we're only looking at auto-accept contracts if (currentDetails != null && currentDetails.contracts.Count() >= MAX_CONTRACTS && !ct.autoAccept) { continue; } // 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 while (validContractTypes.Count > 0) { ContractType selectedContractType = null; // Pick one of the contract types based on their weight double value = rand.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; } // First, check the basic requirements if (!selectedContractType.MeetBasicRequirements(templateContract)) { LoggingUtil.LogVerbose(this, selectedContractType.name + " was not generated: basic requirements not met."); validContractTypes.Remove(selectedContractType); totalWeight -= selectedContractType.weight; yield return null; continue; } // Try to refresh non-deterministic values before we check extended requirements OnInitializeValues.Fire(); LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel; LoggingUtil.LogLevel newLogLevel = selectedContractType.trace ? LoggingUtil.LogLevel.VERBOSE : LoggingUtil.logLevel; bool failure = false; 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(selectedContractType.dataNode); for (ContractGroup g = selectedContractType.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 = " + selectedContractType.name); foreach (string val in iter) { lastKey = selectedContractType.name + "[" + val + "]"; // Clear temp stuff LoggingUtil.logLevel = origLogLevel; ConfiguredContract.currentContract = null; if (val == null) { LoggingUtil.LogVerbose(this, selectedContractType.name + " was not generated: non-deterministic expression failure."); validContractTypes.Remove(selectedContractType); totalWeight -= selectedContractType.weight; yield return null; failure = true; break; } else { yield return null; } // Re set up LoggingUtil.logLevel = newLogLevel; ConfiguredContract.currentContract = templateContract; } } finally { LoggingUtil.logLevel = origLogLevel; ConfiguredContract.currentContract = null; } if (failure) { OnInitializeFail.Fire(); continue; } // Store unique data foreach (string key in selectedContractType.uniquenessChecks.Keys) { templateContract.uniqueData[key] = selectedContractType.dataNode[key]; } // Check the requirements for our selection if (selectedContractType.MeetExtendedRequirements(templateContract, selectedContractType) && templateContract.Initialize(selectedContractType)) { yield return templateContract; yield break; } // Remove the selection, and try again else { LoggingUtil.LogVerbose(this, selectedContractType.name + " was not generated: requirement not met."); validContractTypes.Remove(selectedContractType); totalWeight -= selectedContractType.weight; templateContract.uniqueData.Clear(); templateContract.contractType = null; } // Take a pause OnInitializeFail.Fire(); yield return null; } }
/// <summary> /// Loads the contract group details from the given config node. /// </summary> /// <param name="configNode">The config node to load from</param> /// <returns>Whether we were successful.</returns> public bool Load(ConfigNode configNode) { try { dataNode = new DataNode(configNode.GetValue("name"), this); LoggingUtil.CaptureLog = true; ConfigNodeUtil.SetCurrentDataNode(dataNode); bool valid = true; string unused; valid &= ConfigNodeUtil.ParseValue<string>(configNode, "name", x => name = x, this); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "displayName", x => displayName = x, this, name); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "minVersion", x => minVersionStr = x, this, ""); valid &= ConfigNodeUtil.ParseValue<int>(configNode, "maxCompletions", x => maxCompletions = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue<int>(configNode, "maxSimultaneous", x => maxSimultaneous = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue<List<string>>(configNode, "disabledContractType", x => disabledContractType = x, this, new List<string>()); valid &= ConfigNodeUtil.ParseValue<Agent>(configNode, "agent", x => agent = x, this, (Agent)null); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "sortKey", x => sortKey = x, this, displayName); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "tip", x => unused = x, this, ""); if (configNode.HasValue("sortKey") && parent == null) { sortKey = displayName; LoggingUtil.LogWarning(this, ErrorPrefix() + ": Using the sortKey field is only applicable on child CONTRACT_GROUP elements"); } if (!string.IsNullOrEmpty(minVersionStr)) { if (Util.Version.VerifyAssemblyVersion("ContractConfigurator", minVersionStr) == null) { valid = false; var ainfoV = Attribute.GetCustomAttribute(typeof(ExceptionLogWindow).Assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute; string title = "Contract Configurator " + ainfoV.InformationalVersion + " Message"; string message = "The contract group '" + name + "' requires at least Contract Configurator " + minVersionStr + " to work, and you are running version " + ainfoV.InformationalVersion + ". Please upgrade Contract Configurator to use the contracts in this group."; DialogGUIButton dialogOption = new DialogGUIButton("Okay", new Callback(DoNothing), true); PopupDialog.SpawnPopupDialog(new MultiOptionDialog(message, title, UISkinManager.GetSkin("default"), dialogOption), false, UISkinManager.GetSkin("default")); } } // Load DATA nodes valid &= dataNode.ParseDataNodes(configNode, this, dataValues, uniquenessChecks); // Do the deferred loads valid &= ConfigNodeUtil.ExecuteDeferredLoads(); // Do post-deferred load warnings if (agent == null) { LoggingUtil.LogWarning(this, ErrorPrefix() + ": Providing the agent field for all CONTRACT_GROUP nodes is highly recommended, as the agent is used to group contracts in Mission Control."); } if (string.IsNullOrEmpty(minVersionStr) || minVersion < ContractConfigurator.ENHANCED_UI_VERSION) { LoggingUtil.LogWarning(this, ErrorPrefix() + ": No minVersion or older minVersion provided. It is recommended that the minVersion is set to at least 1.15.0 to turn important warnings for deprecated functionality into errors."); } if (!configNode.HasValue("displayName")) { LoggingUtil.LogWarning(this, ErrorPrefix() + ": No display name provided. A display name is recommended, as it is used in the Mission Control UI."); } config = configNode.ToString(); log += LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; // Load child groups foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "CONTRACT_GROUP")) { ContractGroup child = null; string childName = childNode.GetValue("name"); try { child = new ContractGroup(childName); } catch (ArgumentException) { LoggingUtil.LogError(this, "Couldn't load CONTRACT_GROUP '" + childName + "' due to a duplicate name."); valid = false; continue; } child.parent = this; valid &= child.Load(childNode); child.dataNode.Parent = dataNode; if (child.hasWarnings) { hasWarnings = true; } } // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, this); // Invalidate children if (!valid) { Invalidate(); } enabled = valid; return valid; } catch { enabled = false; throw; } }
/// <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; } }
private void ContractGroupLine(ContractGroup contractGroup, int indent = 0) { string identifier = contractGroup == null ? "" : contractGroup.name; if (!contractGroupDetails.ContainsKey(identifier)) { contractGroupDetails[identifier] = new ContractGroupDetails(contractGroup); } ContractGroupDetails details = contractGroupDetails[identifier]; GUILayout.BeginHorizontal(); GUILayout.Label("", contractRegularText, GUILayout.ExpandWidth(false), GUILayout.Width((indent+1) * 16)); string groupName = contractGroup == null ? "No Group" : contractGroup.displayName; GUILayout.Label(groupName, details.enabled ? contractRegularText : contractDisabledText, GUILayout.ExpandWidth(true)); if (contractGroup != null && contractGroup.parent == null) { bool enabled = GUILayout.Toggle(details.enabled, new GUIContent("", "Click to " + (details.enabled ? "disable " : "enable ") + contractGroup.displayName + " contracts."), contractToggleStyle, GUILayout.ExpandWidth(false)); if (enabled != details.enabled) { details.enabled = enabled; if (enabled) { foreach (KeyValuePair<Type, StockContractDetails> pair in stockContractDetails. Where(p => ContractDisabler.DisablingGroups(p.Key).Contains(contractGroup))) { pair.Value.enabled = false; ContractDisabler.SetContractState(pair.Key, false); } } else { foreach (KeyValuePair<Type, StockContractDetails> pair in stockContractDetails. Where(p => ContractDisabler.DisablingGroups(p.Key).Contains(contractGroup) && ContractDisabler.DisablingGroups(p.Key).All(g => !IsEnabled(g)))) { pair.Value.enabled = true; ContractDisabler.SetContractState(pair.Key, true); } } } } GUILayout.EndHorizontal(); }
public ContractType(string name) { this.name = name; contractTypes.Add(name, this); // Member defaults group = null; agent = null; minExpiry = 0; maxExpiry = 0; deadline = 0; cancellable = true; declinable = true; autoAccept = false; prestige = new List<Contract.ContractPrestige>(); maxCompletions = 0; maxSimultaneous = 0; rewardScience = 0.0f; rewardReputation = 0.0f; rewardFunds = 0.0f; failureReputation = 0.0f; failureFunds = 0.0f; advanceFunds = 0.0f; weight = 1.0; enabled = true; }
public ContractGroupDetails(ContractGroup group) { this.group = group; }
protected bool CheckContractGroup(ConfiguredContract contract, ContractGroup group) { if (group != null) { // Check the group is enabled if (!ContractConfiguratorSettings.IsEnabled(group)) { throw new ContractRequirementException("Contract group " + group.name + " is not enabled."); } IEnumerable<ConfiguredContract> contractList = ContractSystem.Instance.GetCurrentContracts<ConfiguredContract>(). Where(c => c.contractType != null); // Special case for pre-loader contracts if (contract.ContractState == Contract.State.Withdrawn) { contractList = contractList.Union(ContractPreLoader.Instance.PendingContracts(contract.Prestige)); contractList = contractList.Where(c => c != contract); } // Check the group active limit int activeContracts = contractList.Count(c => c.contractType != null && group.BelongsToGroup(c.contractType)); if (contract.ContractState == Contract.State.Offered || contract.ContractState == Contract.State.Active) { activeContracts--; } if (group.maxSimultaneous != 0 && activeContracts >= group.maxSimultaneous) { throw new ContractRequirementException("Too many active contracts in group (" + group.name + ")."); } // Check the group completed limit if (group.maxCompletions != 0) { int finishedContracts = ContractSystem.Instance.GetCompletedContracts<ConfiguredContract>().Count(c => c.contractType != null && group.BelongsToGroup(c.contractType)); if (finishedContracts + activeContracts >= maxCompletions) { throw new ContractRequirementException("Too many completed contracts in group (" + group.name + ")."); } } return CheckContractGroup(contract, group.parent); } return true; }
/// <summary> /// Loads the contract type details from the given config node. /// </summary> /// <param name="configNode">The config node to load from.</param> /// <returns>Whether the load was successful.</returns> public bool Load(ConfigNode configNode) { LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel; try { // Logging on LoggingUtil.CaptureLog = true; dataNode = new DataNode(configNode.GetValue("name"), this); ConfigNodeUtil.SetCurrentDataNode(dataNode); bool valid = true; valid &= ConfigNodeUtil.ParseValue<string>(configNode, "name", x => name = x, this); // Try to turn on trace mode valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "trace", x => trace = x, this, false); if (trace) { LoggingUtil.logLevel = LoggingUtil.LogLevel.VERBOSE; LoggingUtil.LogWarning(this, "Tracing enabled for contract type " + name); } // Load contract text details valid &= ConfigNodeUtil.ParseValue<ContractGroup>(configNode, "group", x => group = x, this, (ContractGroup)null); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "title", x => title = x, this); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "tag", x => tag = x, this, ""); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "description", x => description = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "topic", x => topic = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "subject", x => subject = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "motivation", x => motivation = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "notes", x => notes = x, this, (string)null); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "synopsis", x => synopsis = x, this); valid &= ConfigNodeUtil.ParseValue<string>(configNode, "completedMessage", x => completedMessage = x, this); // Load optional attributes valid &= ConfigNodeUtil.ParseValue<Agent>(configNode, "agent", x => agent = x, this, (Agent)null); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "minExpiry", x => minExpiry = x, this, 1.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "maxExpiry", x => maxExpiry = x, this, 7.0f, x => Validation.GE(x, minExpiry)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "deadline", x => deadline = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "cancellable", x => cancellable = x, this, true); valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "declinable", x => declinable = x, this, true); valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "autoAccept", x => autoAccept = x, this, false); valid &= ConfigNodeUtil.ParseValue<List<Contract.ContractPrestige>>(configNode, "prestige", x => prestige = x, this, new List<Contract.ContractPrestige>()); valid &= ConfigNodeUtil.ParseValue<CelestialBody>(configNode, "targetBody", x => targetBody = x, this, (CelestialBody)null); valid &= ConfigNodeUtil.ParseValue<int>(configNode, "maxCompletions", x => maxCompletions = x, this, 0, x => Validation.GE(x, 0)); valid &= ConfigNodeUtil.ParseValue<int>(configNode, "maxSimultaneous", x => maxSimultaneous = x, this, 0, x => Validation.GE(x, 0)); // Load rewards valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardFunds", x => rewardFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardReputation", x => rewardReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardScience", x => rewardScience = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "failureFunds", x => failureFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "failureReputation", x => failureReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f)); valid &= ConfigNodeUtil.ParseValue<float>(configNode, "advanceFunds", x => advanceFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f)); // Load other values valid &= ConfigNodeUtil.ParseValue<double>(configNode, "weight", x => weight = x, this, 1.0, x => Validation.GE(x, 0.0f)); // Load DATA nodes valid &= DataNode.ParseDataNodes(configNode, this, dataValues, uniqueValues); // Check for unexpected values - always do this last valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, this); log = LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; // Load parameters foreach (ConfigNode contractParameter in ConfigNodeUtil.GetChildNodes(configNode, "PARAMETER")) { ParameterFactory paramFactory = null; valid &= ParameterFactory.GenerateParameterFactory(contractParameter, this, out paramFactory); if (paramFactory != null) { paramFactories.Add(paramFactory); if (paramFactory.hasWarnings) { hasWarnings = true; } } } // Load behaviours foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "BEHAVIOUR")) { BehaviourFactory behaviourFactory = null; valid &= BehaviourFactory.GenerateBehaviourFactory(requirementNode, this, out behaviourFactory); if (behaviourFactory != null) { behaviourFactories.Add(behaviourFactory); if (behaviourFactory.hasWarnings) { hasWarnings = true; } } } // Load requirements foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT")) { ContractRequirement requirement = null; valid &= ContractRequirement.GenerateRequirement(requirementNode, this, out requirement); if (requirement != null) { requirements.Add(requirement); if (requirement.hasWarnings) { hasWarnings = true; } } } // Logging on LoggingUtil.CaptureLog = true; // Check we have at least one valid parameter if (paramFactories.Count() == 0) { LoggingUtil.LogError(this.GetType(), ErrorPrefix() + ": Need at least one parameter for a contract!"); valid = false; } // Do the deferred loads valid &= ConfigNodeUtil.ExecuteDeferredLoads(); config = configNode.ToString(); hash = config.GetHashCode(); enabled = valid; log += LoggingUtil.capturedLog; LoggingUtil.CaptureLog = false; return valid; } catch { enabled = false; throw; } finally { LoggingUtil.logLevel = origLogLevel; loaded = true; } }
private static void GroupGui(ContractGroup contractGroup, int indent) { if (contractGroup != null) { GUILayout.BeginHorizontal(); if (indent != 0) { GUILayout.Label("", GUILayout.ExpandWidth(false), GUILayout.Width(indent * 16)); } if (GUILayout.Button(contractGroup.expandInDebug ? "-" : "+", GUILayout.Width(20), GUILayout.Height(20))) { contractGroup.expandInDebug = !contractGroup.expandInDebug; } GUIStyle style = greenLabel; if (!contractGroup.enabled) { style = redLabel; } else { if (contractGroup.hasWarnings) { style = yellowLabel; } foreach (ContractType contractType in guiContracts.Where(ct => contractGroup == null ? ct.group == null : contractGroup.BelongsToGroup(ct))) { if (!contractType.enabled) { style = redLabel; break; } else if (contractType.hasWarnings) { style = yellowLabel; } } } GUILayout.Label(new GUIContent(contractGroup.ToString(), DebugInfo(contractGroup)), style); GUILayout.EndHorizontal(); } if (contractGroup == null || contractGroup.expandInDebug) { // Child groups if (contractGroup != null) { foreach (ContractGroup childGroup in ContractGroup.AllGroups.Where(g => g != null && g.parent != null && g.parent.name == contractGroup.name).OrderBy(cg => cg.name)) { GroupGui(childGroup, indent + 1); } } // Child contract types foreach (ContractType contractType in guiContracts.Where(ct => ct.group == contractGroup).OrderBy(ct => ct.name)) { GUILayout.BeginHorizontal(); if (contractGroup != null) { GUILayout.Label("", GUILayout.ExpandWidth(false), GUILayout.Width((indent + 1) * 16)); } if (GUILayout.Button(contractType.expandInDebug ? "-" : "+", GUILayout.Width(20), GUILayout.Height(20))) { contractType.expandInDebug = !contractType.expandInDebug; } GUILayout.Label(new GUIContent(contractType.ToString(), DebugInfo(contractType)), contractType.enabled ? contractType.hasWarnings ? yellowLabel : GUI.skin.label : redLabel); GUILayout.EndHorizontal(); if (contractType.expandInDebug) { // Output children ParamGui(contractType, contractType.ParamFactories, indent + (contractGroup == null ? 1 : 2)); RequirementGui(contractType, contractType.Requirements, indent + (contractGroup == null ? 1 : 2)); BehaviourGui(contractType, contractType.BehaviourFactories, indent + (contractGroup == null ? 1 : 2)); GUILayout.Space(8); } } } }
protected bool CheckContractGroup(ConfiguredContract contract, ContractGroup group) { if (group != null) { // Check the group is enabled if (!ContractConfiguratorSettings.IsEnabled(group)) { throw new ContractRequirementException("Contract group " + group.name + " is not enabled."); } // Check the group active limit int activeContracts = ContractSystem.Instance.GetCurrentContracts<ConfiguredContract>().Count(c => c.contractType != null && group.BelongsToGroup(c.contractType)); if (contract.ContractState == Contract.State.Offered || contract.ContractState == Contract.State.Active) { activeContracts--; } if (group.maxSimultaneous != 0 && activeContracts >= group.maxSimultaneous) { throw new ContractRequirementException("Too many active contracts in group (" + group.name + ")."); } // Check the group completed limit if (group.maxCompletions != 0) { int finishedContracts = ContractSystem.Instance.GetCompletedContracts<ConfiguredContract>().Count(c => c.contractType != null && group.BelongsToGroup(c.contractType)); if (finishedContracts + activeContracts >= maxCompletions) { throw new ContractRequirementException("Too many completed contracts in group (" + group.name + ")."); } } return CheckContractGroup(contract, group.parent); } return true; }
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); } }