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); } // Workaround for agencies defined without a title if (agent.Title == null) { agentField.SetValue(agent, agent.Name); } // 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; } }
/// <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> /// 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); dataNode.AddValue("isLiteral", true); 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> /// Checks if the "basic" requirements that shouldn't change due to expressions are met. /// </summary> /// <param name="contract">The contract</param> /// <returns>Whether the contract can be offered.</returns> public bool MeetBasicRequirements(ConfiguredContract contract) { LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel; try { // Turn tracing on if (trace) { LoggingUtil.logLevel = LoggingUtil.LogLevel.VERBOSE; LoggingUtil.LogWarning(this, "Tracing enabled for contract type " + name); } // Check funding if (advanceFunds < 0) { CurrencyModifierQuery q = new CurrencyModifierQuery(TransactionReasons.ContractAdvance, -advanceFunds, 0.0f, 0.0f); GameEvents.Modifiers.OnCurrencyModifierQuery.Fire(q); float fundsRequired = advanceFunds + q.GetEffectDelta(Currency.Funds); if (!Funding.CanAfford(fundsRequired)) { throw new ContractRequirementException("Can't afford contract advance cost."); } } // Check expiry if ((contract.ContractState == Contract.State.Offered || contract.ContractState == Contract.State.Withdrawn) && Planetarium.fetch != null && contract.DateExpire < Planetarium.fetch.time) { throw new ContractRequirementException("Expired contract."); } // Checks for maxSimultaneous/maxCompletions if (maxSimultaneous != 0 || maxCompletions != 0) { IEnumerable <ConfiguredContract> contractList = ConfiguredContract.CurrentContracts. Where(c => c.contractType != null && c.contractType.name == name && c != contract); // Check if we're breaching the active limit int activeContracts = contractList.Count(); if (maxSimultaneous != 0 && activeContracts >= maxSimultaneous) { throw new ContractRequirementException("Too many active contracts."); } // Check if we're breaching the completed limit if (maxCompletions != 0) { if (ActualCompletions() + activeContracts >= maxCompletions) { throw new ContractRequirementException("Too many completed/active/offered contracts."); } } } // Check the group values if (group != null) { CheckContractGroup(contract, group); } return(true); } catch (ContractRequirementException e) { LoggingUtil.LogLevel level = contract.ContractState == Contract.State.Active ? LoggingUtil.LogLevel.INFO : contract.contractType != null ? LoggingUtil.LogLevel.DEBUG : LoggingUtil.LogLevel.VERBOSE; string prefix = contract.contractType != null ? "Cancelling contract of type " + name + " (" + contract.Title + "): " : "Didn't generate contract of type " + name + ": "; LoggingUtil.Log(level, this.GetType(), prefix + e.Message); return(false); } catch { LoggingUtil.LogError(this, "Exception while attempting to check requirements of contract type " + name); throw; } finally { LoggingUtil.logLevel = origLogLevel; loaded = true; } }
/// <summary> /// Loads debugging configurations. /// </summary> /// public static void LoadDebuggingConfig() { UnityEngine.Debug.Log("[INFO] ContractConfigurator.LoggingUtil: Loading DebuggingConfig node."); // Don't know why .GetConfigNode("CC_DEBUGGING") returns null, using .GetConfigNodes("CC_DEBUGGING") works fine. ConfigNode[] debuggingConfigs = GameDatabase.Instance.GetConfigNodes("CC_DEBUGGING"); if (debuggingConfigs.Length > 0) { try { // Fetch config ConfigNode debuggingConfig = debuggingConfigs[0]; // Set LogLevel if (debuggingConfig.HasValue("logLevel")) { LoggingUtil.logLevel = (LoggingUtil.LogLevel)Enum.Parse(typeof(LoggingUtil.LogLevel), debuggingConfig.GetValue("logLevel"), true); LoggingUtil.LogInfo(typeof(LoggingUtil), StringBuilderCache.Format("Set LogLevel = {0}", LoggingUtil.logLevel)); } // Fetch specific loglevels for given types foreach (ConfigNode levelExceptionNode in debuggingConfig.GetNodes("ADD_LOGLEVEL_EXCEPTION")) { if (levelExceptionNode.HasValue("type") && levelExceptionNode.HasValue("logLevel")) { // Fetch full type name - just search and find the matching one while // ignoring namespace string typeName = levelExceptionNode.GetValue("type"); Type type = null; foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { try { foreach (Type t in a.GetTypes()) { if (t.Name == typeName || t.Name.StartsWith(typeName + '`')) { type = t; break; } } } catch (Exception e) { UnityEngine.Debug.LogWarning(StringBuilderCache.Format("[WARNING] Error loading types from assembly {0}: {1}", a.FullName, e.Message)); } } if (type != null) { LoggingUtil.LogLevel logLevel = (LoggingUtil.LogLevel)Enum.Parse(typeof(LoggingUtil.LogLevel), levelExceptionNode.GetValue("logLevel"), true); LoggingUtil.AddSpecificLogLevel(type, logLevel); LoggingUtil.LogDebug(typeof(LoggingUtil), "Added log level override ({0} => {1})", type.Name, logLevel); } else { UnityEngine.Debug.LogWarning(StringBuilderCache.Format("[WARNING] ContractConfigurator.LoggingUtil: Couldn't find Type with name: '{0}'", typeName)); } } else { UnityEngine.Debug.LogWarning("[WARNING] ContractConfigurator.LoggingUtil: Couldn't load specific LogLevel node, type or logLevel not given!"); } } LoggingUtil.LogInfo(typeof(LoggingUtil), "Debugging config loaded!"); } catch (Exception e) { LoggingUtil.ClearSpecificLogLevel(); LoggingUtil.logLevel = LoggingUtil.LogLevel.INFO; LoggingUtil.LogWarning(typeof(LoggingUtil), StringBuilderCache.Format("Debugging Config failed to load! Message: '{0}' Set LogLevel to INFO and cleaned specific LogLevels", e.Message)); } } else { LoggingUtil.logLevel = LoggingUtil.LogLevel.INFO; LoggingUtil.LogWarning(typeof(LoggingUtil), "No debugging config found! LogLevel set to INFO"); } }