EVAManager: Cleaned up logging substantially; reduced the number of string literals in favor of a few consts.
EVAManager: Cleaned up logging substantially; reduced the number of string literals in favor of a few consts.

// EVAManager // EVAManager
// //
// EVAManager.cs // EVAManager.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ToadicusTools; using ToadicusTools;
using UnityEngine; using UnityEngine;
   
namespace EVAManager namespace EVAManager
{ {
[KSPAddon(KSPAddon.Startup.MainMenu, true)] [KSPAddon(KSPAddon.Startup.MainMenu, true)]
public class EVAManager : MonoBehaviour public class EVAManager : MonoBehaviour
{ {
private const string patchPattern = @"^((DELETE|EDIT)_)?EVA_([a-zA-Z_]+)(\[(.+)\])?"; private const string patchPattern = @"^((DELETE|EDIT)_)?EVA_([a-zA-Z_]+)(\[(.+)\])?";
private const int operatorIdx = 2; private const int operatorIdx = 2;
private const int classIdx = 3; private const int classIdx = 3;
private const int nameIdx = 5; private const int nameIdx = 5;
   
private const string empty = ""; private const string empty = "";
   
  private const string MODULE = "MODULE";
  private const string RESOURCE = "RESOURCE";
   
private List<ConfigAction> evaConfigs; private List<ConfigAction> evaConfigs;
private List<ConfigAction> passQueue; private List<ConfigAction> passQueue;
   
private Part evaPart; private Part evaPart;
   
private Pass pass; private Pass pass;
   
public void Awake() public void Awake()
{ {
pass = Pass.Collect; pass = Pass.Collect;
this.passQueue = new List<ConfigAction>(); this.passQueue = new List<ConfigAction>();
} }
   
public virtual void Update() public virtual void Update()
{ {
if (!PartLoader.Instance.IsReady() || PartResourceLibrary.Instance == null) if (!PartLoader.Instance.IsReady() || PartResourceLibrary.Instance == null)
{ {
return; return;
} }
   
#if DEBUG #if DEBUG
Tools.DebugLogger log; Tools.DebugLogger log;
#endif #endif
   
if (this.passQueue.Count > 0 && this.evaConfigs != null) if (this.passQueue.Count > 0 && this.evaConfigs != null)
{ {
this.evaConfigs.AddRange(this.passQueue); this.evaConfigs.AddRange(this.passQueue);
   
this.passQueue.Clear(); this.passQueue.Clear();
} }
   
switch (pass) switch (pass)
{ {
case Pass.Collect: case Pass.Collect:
foreach (var loadedPart in PartLoader.LoadedPartsList) foreach (var loadedPart in PartLoader.LoadedPartsList)
{ {
if (loadedPart.name.ToLower() == "kerbaleva") if (loadedPart.name.ToLower() == "kerbaleva")
{ {
Tools.PostDebugMessage(this, "Found {0}", loadedPart.name); this.LogDebug("Found {0}", loadedPart.name);
   
evaPart = loadedPart.partPrefab; evaPart = loadedPart.partPrefab;
   
#if DEBUG #if DEBUG
log = Tools.DebugLogger.New(this); log = Tools.DebugLogger.New(this);
   
log.AppendLine("Modules before run:"); log.AppendLine("Modules before run:");
   
foreach (var m in evaPart.GetComponents<PartModule>()) foreach (var m in evaPart.GetComponents<PartModule>())
{ {
log.Append('\t'); log.Append('\t');
log.Append(m.GetType().Name); log.Append(m.GetType().Name);
log.Append('\n'); log.Append('\n');
} }
   
log.AppendLine("Resources before run:"); log.AppendLine("Resources before run:");
   
foreach (var r in evaPart.GetComponents<PartResource>()) foreach (var r in evaPart.GetComponents<PartResource>())
{ {
log.Append('\t'); log.Append('\t');
log.AppendFormat("Name: {0}, amount: {1}, maxAmount: {2}", log.AppendFormat("Name: {0}, amount: {1}, maxAmount: {2}",
r.resourceName, r.amount, r.maxAmount); r.resourceName, r.amount, r.maxAmount);
log.Append('\n'); log.Append('\n');
} }
   
log.Print(); log.Print();
#endif #endif
   
break; break;
} }
} }
   
evaConfigs = new List<ConfigAction>(); evaConfigs = new List<ConfigAction>();
   
Regex rgx = new Regex(patchPattern); Regex rgx = new Regex(patchPattern);
   
foreach (var urlConfig in GameDatabase.Instance.root.AllConfigs) foreach (var urlConfig in GameDatabase.Instance.root.AllConfigs)
{ {
Tools.PostDebugMessage( Tools.PostDebugMessage(
this, this,
"Checking urlconfig; name: {0}, type: {1}, config.name: {2}", "Checking urlconfig; name: {0}, type: {1}, config.name: {2}",
urlConfig.name, urlConfig.name,
urlConfig.type, urlConfig.type,
urlConfig.config.name); urlConfig.config.name);
   
Match match = rgx.Match(urlConfig.type); Match match = rgx.Match(urlConfig.type);
   
Tools.PostDebugMessage(this, "Found {0}match for {1}{2}", this.LogDebug("Found {0}match for {1}{2}",
!match.Success ? "no " : "", !match.Success ? "no " : "",
urlConfig.type, urlConfig.type,
!match.Success ? "" : string.Format( !match.Success ? "" : string.Format(
"\nOp: {0}, Class: {1}, Name: {2}", "\nOp: {0}, Class: {1}, Name: {2}",
match.Groups[operatorIdx], match.Groups[operatorIdx],
match.Groups[classIdx], match.Groups[classIdx],
match.Groups[nameIdx]) match.Groups[nameIdx])
); );
   
if (match.Success) if (match.Success)
{ {
string op = match.Groups[operatorIdx].Value; string op = match.Groups[operatorIdx].Value;
string classType = match.Groups[classIdx].Value; string classType = match.Groups[classIdx].Value;
string matchName = match.Groups[nameIdx].Value; string matchName = match.Groups[nameIdx].Value;
   
evaConfigs.Add(new ConfigAction(op, classType, matchName, urlConfig.config)); evaConfigs.Add(new ConfigAction(op, classType, matchName, urlConfig.config));
} }
} }
   
pass = Pass.Delete; pass = Pass.Delete;
break; break;
case Pass.Delete: case Pass.Delete:
foreach (ConfigAction action in this.evaConfigs) foreach (ConfigAction action in this.evaConfigs)
{ {
if (action.Operator == "DELETE") if (action.Operator == "DELETE")
{ {
Tools.PostDebugMessage(this, "Trying delete action on {0}", action); this.LogDebug("Trying delete action on {0}", action);
   
if (action.MatchName == string.Empty) if (action.MatchName == string.Empty)
{ {
Debug.LogWarning(string.Format( this.LogWarning("Match name required for 'delete' action but not present; ignoring.");
"[{0}] match name required for 'delete' action but not present; ignoring.",  
this.GetType().Name));  
continue; continue;
} }
   
switch (action.ClassType) switch (action.ClassType)
{ {
case "MODULE": case MODULE:
this.delModuleByName(action.MatchName); this.delModuleByName(action.MatchName);
break; break;
case "RESOURCE": case RESOURCE:
this.delResourceByName(action.MatchName); this.delResourceByName(action.MatchName);
break; break;
default: default:
Debug.LogWarning(string.Format( this.LogWarning("Class type '{0}' not implemented for 'delete' action.",
"[{0}] Class type '{1}' not implemented for 'delete' action.", action.ClassType);
this.GetType().Name,  
action.ClassType));  
continue; continue;
} }
} }
} }
   
pass = Pass.Edit; pass = Pass.Edit;
break; break;
case Pass.Edit: case Pass.Edit:
foreach (ConfigAction action in this.evaConfigs) foreach (ConfigAction action in this.evaConfigs)
{ {
if (action.Operator == "EDIT") if (action.Operator == "EDIT")
{ {
Tools.PostDebugMessage(this, "Trying edit action on {0}", action); this.LogDebug("Trying edit action on {0}", action);
   
if (action.MatchName == string.Empty) if (action.MatchName == string.Empty)
{ {
Debug.LogWarning(string.Format( this.LogWarning("Match name required for 'edit' action but not present; ignoring.");
"[{0}] match name required for 'edit' action but not present; ignoring.",  
this.GetType().Name));  
continue; continue;
} }
   
switch (action.ClassType) switch (action.ClassType)
{ {
case "MODULE": case MODULE:
this.editModuleByNameFromConfig(action.MatchName, action.Node); this.editModuleByNameFromConfig(action.MatchName, action.Node);
break; break;
case "RESOURCE": case RESOURCE:
this.editResourceByNameFromConfig(action.MatchName, action.Node); this.editResourceByNameFromConfig(action.MatchName, action.Node);
break; break;
default: default:
Debug.LogWarning(string.Format( this.LogWarning("Class type '{0}' not implemented for 'delete' action.",
"[{0}] Class type '{1}' not implemented for 'delete' action.", action.ClassType);
this.GetType().Name,  
action.ClassType));  
continue; continue;
} }
} }
} }
pass = Pass.Insert; pass = Pass.Insert;
break; break;
case Pass.Insert: case Pass.Insert:
foreach (ConfigAction action in this.evaConfigs) foreach (ConfigAction action in this.evaConfigs)
{ {
if (action.Operator == empty) if (action.Operator == empty)
{ {
if (action.MatchName != string.Empty) if (action.MatchName != string.Empty)
{ {
Debug.LogWarning(string.Format( this.LogWarning("match name ('{0}') not used for 'add' action; ignoring.",
"[{0}] match name ('{1}') not used for 'add' action; ignoring.", action.MatchName);
this.GetType().Name,  
action.MatchName));  
} }
   
switch (action.ClassType) switch (action.ClassType)
{ {
case "MODULE": case MODULE:
this.addModuleFromConfig(action.Node); this.addModuleFromConfig(action.Node);
break; break;
case "RESOURCE": case RESOURCE:
this.addResourceFromConfig(action.Node); this.addResourceFromConfig(action.Node);
break; break;
default: default:
Debug.LogWarning(string.Format( this.LogWarning("Class type '{0}' not implemented for 'add' action.",
"[{0}] Class type '{1}' not implemented for 'add' action.", action.ClassType);
this.GetType().Name,  
action.ClassType));  
continue; continue;
} }
} }
} }
pass = Pass.Done; pass = Pass.Done;
break; break;
case Pass.Done: case Pass.Done:
#if DEBUG #if DEBUG
log = Tools.DebugLogger.New(this); log = Tools.DebugLogger.New(this);
   
log.AppendLine("Modules after run:"); log.AppendLine("Modules after run:");
   
foreach (var m in evaPart.GetComponents<PartModule>()) foreach (var m in evaPart.GetComponents<PartModule>())
{ {
log.Append('\t'); log.Append('\t');
log.Append(m.GetType().Name); log.Append(m.GetType().Name);
log.Append('\n'); log.Append('\n');
} }
   
log.AppendLine("Resources after run:"); log.AppendLine("Resources after run:");
   
foreach (var r in evaPart.GetComponents<PartResource>()) foreach (var r in evaPart.GetComponents<PartResource>())
{ {
log.Append('\t'); log.Append('\t');
log.AppendFormat("Name: {0}, amount: {1}, maxAmount: {2}", log.AppendFormat("Name: {0}, amount: {1}, maxAmount: {2}",
r.resourceName, r.amount, r.maxAmount); r.resourceName, r.amount, r.maxAmount);
log.Append('\n'); log.Append('\n');
} }
   
log.Print(); log.Print();
#endif #endif
   
GameObject.Destroy(this); GameObject.Destroy(this);
   
Tools.PostDebugMessage(this, "Destruction Requested."); this.LogDebug("Destruction Requested.");
break; break;
} }
} }
   
private void addModuleFromConfig(ConfigNode evaModuleNode) private void addModuleFromConfig(ConfigNode evaModuleNode)
{ {
string moduleName; string moduleName;
   
if (evaModuleNode.TryGetValue("name", out moduleName)) if (evaModuleNode.TryGetValue("name", out moduleName))
{ {
if (evaPart.GetComponents<PartModule>().Any(m => m.GetType().Name == moduleName)) if (evaPart.GetComponents<PartModule>().Any(m => m.GetType().Name == moduleName))
{ {
Debug.LogWarning(string.Format( this.LogWarning("Skipping module {1}: already present in kerbalEVA", moduleName);
"[{0}] Skipping module {1}: already present in kerbalEVA",  
this.GetType().Name,  
moduleName  
));  
return; return;
} }
   
Type moduleClass = AssemblyLoader.GetClassByName(typeof(PartModule), moduleName); Type moduleClass = AssemblyLoader.GetClassByName(typeof(PartModule), moduleName);
   
if (moduleClass == null) if (moduleClass == null)
{ {
Debug.LogWarning(string.Format( this.LogWarning("Skipping module {0}: class not found in loaded assemblies.", moduleName);
"[{0}] Skipping module {1}: class not found in loaded assemblies.",  
this.GetType().Name,  
moduleName  
));  
return; return;
} }
   
try try
{ {
PartModule evaModule = evaPart.gameObject.AddComponent(moduleClass) PartModule evaModule = evaPart.gameObject.AddComponent(moduleClass)
as PartModule; as PartModule;
   
var awakeMethod = typeof(PartModule).GetMethod("Awake", var awakeMethod = typeof(PartModule).GetMethod("Awake",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance System.Reflection.BindingFlags.Instance
); );
   
awakeMethod.Invoke(evaModule, new object[] {}); awakeMethod.Invoke(evaModule, new object[] {});
   
evaModule.Load(evaModuleNode); evaModule.Load(evaModuleNode);
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.Log(string.Format( this.LogError("Handled exception {0} while adding modules to kerbalEVA.", ex.GetType().Name);
"TweakableEVAManager handled exception {0} while adding modules to kerbalEVA.",  
ex.GetType().Name  
));  
   
#if DEBUG #if DEBUG
Debug.LogException(ex); Debug.LogException(ex);
#endif #endif
} }
   
if (evaPart.GetComponents<PartModule>().Any(m => m.GetType().Name == moduleName)) if (evaPart.GetComponents<PartModule>().Any(m => m.GetType().Name == moduleName))
{ {
Debug.Log(string.Format("[{0}] added module {1} to kerbalEVA part.", this.Log("Added module {0} to kerbalEVA part.", moduleName);
this.GetType().Name,  
moduleName  
));  
} }
else else
{ {
Debug.LogWarning(string.Format( this.LogWarning("Failed to add {0} to kerbalEVA part.", moduleName);
"[{0}] failed to add {1} to kerbalEVA part.",  
this.GetType().Name,  
moduleName  
));  
} }
} }
else else
{ {
Debug.Log(string.Format( this.LogWarning("Skipping malformed EVA_MODULE node: missing 'name' field.");
"[{0}] Skipping malformed EVA_MODULE node: missing 'name' field.",  
this.GetType().Name  
));  
return; return;
} }
} }
   
private void addResourceFromConfig(ConfigNode evaResourceNode) private void addResourceFromConfig(ConfigNode evaResourceNode)
{ {
string resourceName; string resourceName;
   
if (evaResourceNode.TryGetValue("name", out resourceName)) if (evaResourceNode.TryGetValue("name", out resourceName))
{ {
Tools.PostDebugMessage(this, "Adding resource '{0}'", resourceName); this.LogDebug("Adding resource '{0}'", resourceName);
   
PartResourceDefinition resourceInfo = PartResourceDefinition resourceInfo =
PartResourceLibrary.Instance.GetDefinition(resourceName); PartResourceLibrary.Instance.GetDefinition(resourceName);
   
if (resourceInfo == null) if (resourceInfo == null)
{ {
Debug.LogWarning(string.Format( this.LogWarning("Skipping resource {0}: definition not present in library.", resourceName);
"[{0}]: Skipping resource {1}: definition not present in library.",  
this.GetType().Name,  
resourceName  
));  
   
return; return;
} }
   
Tools.PostDebugMessage(this, "Resource '{0}' is in library.", resourceName); this.LogDebug("Resource '{0}' is in library.", resourceName);
   
if (evaPart.GetComponents<PartResource>().Any(r => r.resourceName == resourceName)) if (evaPart.GetComponents<PartResource>().Any(r => r.resourceName == resourceName))
{ {
Debug.LogWarning(string.Format( this.LogWarning("Skipping resource {0}: already present in kerbalEVA.", resourceName);
"[{0}] Skipping resource {1}: already present in kerbalEVA.",  
this.GetType().Name,  
resourceName  
));  
   
return; return;
} }
   
Tools.PostDebugMessage(this, "Resource '{0}' is not present.", resourceName); this.LogDebug("Resource '{0}' is not present.", resourceName);
   
PartResource resource = evaPart.gameObject.AddComponent<EVAPartResource>(); PartResource resource = evaPart.gameObject.AddComponent<EVAPartResource>();
   
Tools.PostDebugMessage(this, "Resource '{0}' component built.", resourceName); this.LogDebug("Resource '{0}' component built.", resourceName);
   
resource.SetInfo(resourceInfo); resource.SetInfo(resourceInfo);
((EVAPartResource)resource).Load(evaResourceNode); ((EVAPartResource)resource).Load(evaResourceNode);
   
Debug.Log(string.Format("[{0}] Added resource {1} to kerbalEVA part.", this.Log("Added resource {0} to kerbalEVA part.", resource.resourceName);
this.GetType().Name,  
resource.resourceName this.LogDebug("Resource '{0}' loaded.", resourceName);
));  
   
Tools.PostDebugMessage(this, "Resource '{0}' loaded.", resourceName);  
} }
else else
{ {
Debug.Log(string.Format( this.Log("Skipping malformed EVA_RESOURCE node: missing 'name' field.");
"[{0}] Skipping malformed EVA_RESOURCE node: missing 'name' field.",  
this.GetType().Name  
));  
return; return;
} }
} }
   
private void delModuleByName(string matchName) private void delModuleByName(string matchName)
{ {
PartModule module = this.matchFirstModuleByName(matchName); PartModule module = this.matchFirstModuleByName(matchName);
   
if (module != null) if (module != null)
{ {
GameObject.Destroy(module); GameObject.Destroy(module);
} }
} }
   
private void delResourceByName(string matchName) private void delResourceByName(string matchName)
{ {
PartResource resource = this.matchFirstResourceByName(matchName); PartResource resource = this.matchFirstResourceByName(matchName);
   
if (resource != null) if (resource != null)
{ {
GameObject.Destroy(resource); GameObject.Destroy(resource);
   
Tools.PostDebugMessage( Tools.PostDebugMessage(
this, this,
"EVA resource {0} marked for destruction.", "EVA resource {0} marked for destruction.",
resource.resourceName); resource.resourceName);
} }
} }
   
private void editModuleByNameFromConfig(string matchName, ConfigNode config) private void editModuleByNameFromConfig(string matchName, ConfigNode config)
{ {
PartModule module = this.matchFirstModuleByName(matchName); PartModule module = this.matchFirstModuleByName(matchName);
   
if (module != null) if (module != null)
{ {
if (config.HasValue("name")) if (config.HasValue("name"))
{ {
config = this.mergeConfigs(module, config); config = this.mergeConfigs(module, config);
   
GameObject.Destroy(module); GameObject.Destroy(module);
   
Tools.PostDebugMessage(this, "EVA module {0} marked for destruction.", module.GetType().Name); this.LogDebug("EVA module {0} marked for destruction.", module.GetType().Name);
   
ConfigAction copyAction = new ConfigAction(empty, "MODULE", empty, config); ConfigAction copyAction = new ConfigAction(empty, MODULE, empty, config);
   
this.passQueue.Add(copyAction); this.passQueue.Add(copyAction);
   
Tools.PostDebugMessage( Tools.PostDebugMessage(
this, this,
"EVA module {0} marked for insertion\n(action: {1})", "EVA module {0} marked for insertion\n(action: {1})",
config.GetValue("name"), config.GetValue("name"),
copyAction copyAction
); );
} }
else else
{ {
this.assignFieldsFromConfig(module, config); this.assignFieldsFromConfig(module, config);
} }
} }
} }
   
private void editResourceByNameFromConfig(string matchName, ConfigNode config) private void editResourceByNameFromConfig(string matchName, ConfigNode config)
{ {
PartResource resource = this.matchFirstResourceByName(matchName); PartResource resource = this.matchFirstResourceByName(matchName);
   
if (resource != null) if (resource != null)
{ {
if (config.HasValue("name")) if (config.HasValue("name"))
{ {
config = this.mergeConfigs(resource, config); config = this.mergeConfigs(resource, config);
   
GameObject.Destroy(resource); GameObject.Destroy(resource);
   
Tools.PostDebugMessage(this, "EVA resource {0} marked for destruction.", resource.resourceName); this.LogDebug("EVA resource {0} marked for destruction.", resource.resourceName);
   
ConfigAction copyAction = new ConfigAction(empty, "RESOURCE", empty, config); ConfigAction copyAction = new ConfigAction(empty, RESOURCE, empty, config);
   
this.passQueue.Add(copyAction); this.passQueue.Add(copyAction);
   
Tools.PostDebugMessage( Tools.PostDebugMessage(
this, this,
"EVA resource {0} marked for insertion\n(action: {1})", "EVA resource {0} marked for insertion\n(action: {1})",
config.GetValue("name"), config.GetValue("name"),
copyAction copyAction
); );
} }
else else
{ {
this.assignFieldsFromConfig(resource, config); this.assignFieldsFromConfig(resource, config);
} }
} }
} }
   
private PartModule matchFirstModuleByName(string matchName) private PartModule matchFirstModuleByName(string matchName)
{ {
Regex rgx = new Regex(@matchName); Regex rgx = new Regex(@matchName);
   
foreach (PartModule module in evaPart.GetComponents<PartModule>()) foreach (PartModule module in evaPart.GetComponents<PartModule>())
{ {
Match match = rgx.Match(module.GetType().Name); Match match = rgx.Match(module.GetType().Name);
   
if (match.Success) if (match.Success)
{ {
return module; return module;
} }
} }
   
return null; return null;
} }
   
private PartResource matchFirstResourceByName(string matchName) private PartResource matchFirstResourceByName(string matchName)
{ {
Regex rgx = new Regex(@matchName); Regex rgx = new Regex(@matchName);
   
foreach (PartResource resource in evaPart.GetComponents<PartResource>()) foreach (PartResource resource in evaPart.GetComponents<PartResource>())
{ {
Match match = rgx.Match(resource.resourceName); Match match = rgx.Match(resource.resourceName);
   
Tools.PostDebugMessage( Tools.PostDebugMessage(
this, this,
"EVA resource {0} is {1}a match for action.", "EVA resource {0} is {1}a match for action.",
resource.resourceName, resource.resourceName,
match.Success ? "" : "not "); match.Success ? "" : "not ");
   
if (match.Success) if (match.Success)
{ {
return resource; return resource;
} }
} }
   
return null; return null;
} }
   
private bool assignFieldsFromConfig(object obj, ConfigNode config) private bool assignFieldsFromConfig(object obj, ConfigNode config)
{ {
bool success = true; bool success = true;
   
foreach (ConfigNode.Value cfgValue in config.values) foreach (ConfigNode.Value cfgValue in config.values)
{ {
try try
{ {
var namedField = obj.GetType().GetField(cfgValue.name, var namedField = obj.GetType().GetField(cfgValue.name,
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.FlattenHierarchy System.Reflection.BindingFlags.FlattenHierarchy
); );
   
if (namedField != null) if (namedField != null)
{ {
var fieldType = namedField.FieldType; var fieldType = namedField.FieldType;
   
object convertedValue = Convert.ChangeType(cfgValue.value, fieldType); object convertedValue = Convert.ChangeType(cfgValue.value, fieldType);
   
namedField.SetValue(obj, convertedValue); namedField.SetValue(obj, convertedValue);
   
success &= true; success &= true;
   
Tools.PostDebugMessage(this, "Assigned field '{0}' with new value '{1}'.", namedField.Name, convertedValue); this.LogDebug("Assigned field '{0}' with new value '{1}'.", namedField.Name, convertedValue);
} }
else else
{ {
Debug.LogWarning(string.Format( this.LogWarning("Failed assigning value '{0}': field not found in class '{1}'",
"[{0}] Failed assigning value '{1}': field not found in class '{2}'",  
this.GetType().Name,  
cfgValue.name, cfgValue.name,
obj.GetType().Name obj.GetType().Name
)); );
   
success &= false; success &= false;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.LogWarning(string.Format( this.LogWarning("Failed assigning value '{0}': {1}", cfgValue.name, ex.Message);
"[{0}] Failed assigning value '{1}': {2}",  
this.GetType().Name,  
cfgValue.name,  
ex.Message  
));  
   
success &= false; success &= false;
   
#if DEBUG #if DEBUG
Debug.LogException(ex); Debug.LogException(ex);
#endif #endif
} }
} }
   
return success; return success;
} }
   
private ConfigNode mergeConfigs(ConfigNode source, ConfigNode target) private ConfigNode mergeConfigs(ConfigNode source, ConfigNode target)
{ {
foreach (ConfigNode.Value value in target.values) foreach (ConfigNode.Value value in target.values)
{ {
if (source.HasValue(value.name)) if (source.HasValue(value.name))
{ {
source.RemoveValue(value.name); source.RemoveValue(value.name);
} }
} }
   
source.CopyTo(target); source.CopyTo(target);
   
return target; return target;
} }
   
private ConfigNode mergeConfigs(PartResource resource, ConfigNode target) private ConfigNode mergeConfigs(PartResource resource, ConfigNode target)
{ {
ConfigNode source = new ConfigNode(); ConfigNode source = new ConfigNode();
   
if (resource is EVAPartResource) if (resource is EVAPartResource)
{ {
((EVAPartResource)resource).Save(source); ((EVAPartResource)resource).Save(source);
} }
else else
{ {
resource.Save(source); resource.Save(source);
} }
   
return this.mergeConfigs(source, target); return this.mergeConfigs(source, target);
} }
   
private ConfigNode mergeConfigs(PartModule module, ConfigNode target) private ConfigNode mergeConfigs(PartModule module, ConfigNode target)
{ {
ConfigNode source = new ConfigNode(); ConfigNode source = new ConfigNode();
   
source.AddValue("name", module.GetType().Name); source.AddValue("name", module.GetType().Name);
   
foreach (var field in module.GetType().GetFields( foreach (var field in module.GetType().GetFields(
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance System.Reflection.BindingFlags.Instance
)) ))
{ {
foreach (object attr in field.GetCustomAttributes(true)) foreach (object attr in field.GetCustomAttributes(true))
{ {
if (attr is KSPField) if (attr is KSPField)
{ {
source.AddValue(field.Name, field.GetValue(module)); source.AddValue(field.Name, field.GetValue(module));
   
break; break;
} }
} }
} }
   
return this.mergeConfigs(source, target); return this.mergeConfigs(source, target);
} }
   
#if DEBUG #if DEBUG
public void OnDestroy() public void OnDestroy()
{ {
Tools.PostDebugMessage(this, "Destroyed."); this.LogDebug("Destroyed.");
} }
#endif #endif
   
private enum Pass private enum Pass
{ {
Collect, Collect,
Delete, Delete,
Edit, Edit,
Insert, Insert,
Done Done
} }
   
internal class ConfigAction internal class ConfigAction
{ {
internal string Operator internal string Operator
{ {
get; get;
private set; private set;
} }
   
internal string ClassType internal string ClassType
{ {
get; get;
private set; private set;
} }
   
internal string MatchName internal string MatchName
{ {
get; get;
private set; private set;
} }
   
internal ConfigNode Node internal ConfigNode Node
{ {
get; get;
private set; private set;
} }
   
private ConfigAction() {} private ConfigAction() {}
   
internal ConfigAction(string op, string classType, string matchName) internal ConfigAction(string op, string classType, string matchName)
{ {
this.Operator = op; this.Operator = op;
this.ClassType = classType; this.ClassType = classType;
this.MatchName = matchName; this.MatchName = matchName;
} }
   
internal ConfigAction(string op, string classType, string matchName, ConfigNode node) internal ConfigAction(string op, string classType, string matchName, ConfigNode node)
: this(op, classType, matchName) : this(op, classType, matchName)
{ {
this.Node = node; this.Node = node;
} }
   
public override string ToString() public override string ToString()
{ {
return string.Format( return string.Format(
"[ConfigAction: Operator: {0}, ClassType: {1}, MatchName: {2}, Node: {3}]", "[ConfigAction: Operator: {0}, ClassType: {1}, MatchName: {2}, Node: {3}]",
this.Operator ?? "null", this.Operator ?? "null",
this.ClassType ?? "null", this.ClassType ?? "null",
this.MatchName ?? "null", this.MatchName ?? "null",
this.Node); this.Node);
} }
} }
} }
} }