/// <summary>Fixes null persistent fields in the module.</summary> /// <remarks>Used to prevent NREs in methods that persist KSP fields.</remarks> /// <param name="module">Module to fix.</param> public static void CleanupFieldsInModule(PartModule module) { // Ensure the module is awaken. Otherwise, any access to base fields list will result in NRE. // HACK: Accessing Fields property of a non-awaken module triggers NRE. If it happens then do // explicit awakening of the *base* module class. try { var unused = module.Fields.GetEnumerator(); } catch { Logger.logWarning("WORKAROUND. Module {0} on part prefab {1} is not awaken. Call Awake on it", module.GetType(), module.part); AwakePartModule(module); } foreach (var field in module.Fields) { var baseField = field as BaseField; if (baseField.isPersistant && baseField.GetValue(module) == null) { var proto = new StandardOrdinaryTypesProto(); var defValue = proto.ParseFromString("", baseField.FieldInfo.FieldType); Logger.logWarning("WORKAROUND. Found null field {0} in module prefab {1}," + " fixing to default value of type {2}: {3}", baseField.name, module.moduleName, baseField.FieldInfo.FieldType, defValue); baseField.SetValue(defValue, module); } } }
/// <summary>Fixes null persistent fields in the module.</summary> /// <remarks>Used to prevent NREs in methods that persist KSP fields.</remarks> /// <param name="module">A module to fix.</param> public static void CleanupFieldsInModule(PartModule module) { foreach (var field in module.Fields) { var baseField = field as BaseField; if (baseField.isPersistant && baseField.GetValue(module) == null) { var proto = new StandardOrdinaryTypesProto(); var defValue = proto.ParseFromString("", baseField.FieldInfo.FieldType); Logger.logWarning("WORKAROUND. Found null field {0} in module prefab {1}," + " fixing to default value of type {2}: {3}", baseField.name, module.moduleName, baseField.FieldInfo.FieldType, defValue); baseField.SetValue(defValue, module); } } }
/// <summary>Fixes null persistent fields in the module.</summary> /// <remarks>Used to prevent NREs in methods that persist KSP fields.</remarks> /// <param name="module">The module to fix.</param> static void CleanupFieldsInModule(PartModule module) { // HACK: Fix uninitialized fields in science lab module. var scienceModule = module as ModuleScienceLab; if (scienceModule != null) { scienceModule.ExperimentData = new List <string>(); DebugEx.Warning( "WORKAROUND. Fix null field in ModuleScienceLab module on the part prefab: {0}", module); } // Ensure the module is awaken. Otherwise, any access to base fields list will result in NRE. // HACK: Accessing Fields property of a non-awaken module triggers NRE. If it happens then do // explicit awakening of the *base* module class. try { module.Fields.GetEnumerator(); } catch { DebugEx.Warning( "WORKAROUND. Module {0} on part prefab is not awaken. Call Awake on it", module); module.Awake(); } foreach (var field in module.Fields) { var baseField = field as BaseField; if (baseField.isPersistant && baseField.GetValue(module) == null) { var proto = new StandardOrdinaryTypesProto(); var defValue = proto.ParseFromString("", baseField.FieldInfo.FieldType); DebugEx.Warning("WORKAROUND. Found null field {0} in module prefab {1}," + " fixing to default value of type {2}: {3}", baseField.name, module, baseField.FieldInfo.FieldType, defValue); baseField.SetValue(defValue, module); } } }
/// <summary>Creates a debug adjustment control for the basic type.</summary> /// <param name="caption">The field caption to show in the dialog.</param> /// <param name="instance"> /// The instance of the object that holds the field to be adjusted via GUI. /// </param> /// <param name="host"> /// The class that should get the member change notifications. If not set, then /// <paramref name="instance"/> will be the target. /// </param> /// <param name="fieldInfo">The field info of the target member.</param> /// <param name="propertyInfo">The property info of the target member.</param> /// <param name="methodInfo">The action member info.</param> public StdTypesDebugGuiControl(string caption, object instance, IHasDebugAdjustables host = null, FieldInfo fieldInfo = null, PropertyInfo propertyInfo = null, MethodInfo methodInfo = null) { Action onBeforeValueUpdateCallback = null; Action onAfterValueUpdateCallback = null; var adjustable = (host as IHasDebugAdjustables) ?? (instance as IHasDebugAdjustables); if (adjustable != null) { onBeforeValueUpdateCallback = adjustable.OnBeforeDebugAdjustablesUpdate; onAfterValueUpdateCallback = adjustable.OnDebugAdjustablesUpdated; } try { if (methodInfo != null) { if (methodInfo.GetParameters().Length > 0) { throw new ArgumentException("Debug action method must be parameterless"); } this.caption = caption; this.action = () => methodInfo.Invoke(instance, new object[0]); } else { this.caption = caption + ":"; this.action = null; var type = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType; if (type == typeof(bool)) { this.control = new HermeticGUIControlBoolean( caption, instance, fieldInfo: fieldInfo, propertyInfo: propertyInfo, onBeforeUpdate: onBeforeValueUpdateCallback, onAfterUpdate: onAfterValueUpdateCallback); } else if (type.IsEnum) { this.control = new HermeticGUIControlSwitch( instance, fieldInfo: fieldInfo, propertyInfo: propertyInfo, onBeforeUpdate: onBeforeValueUpdateCallback, onAfterUpdate: onAfterValueUpdateCallback, useOwnLayout: false); } else { var proto = new StandardOrdinaryTypesProto(); if (proto.CanHandle(type)) { this.control = new HermeticGUIControlText( instance, fieldInfo: fieldInfo, propertyInfo: propertyInfo, onBeforeUpdate: onBeforeValueUpdateCallback, onAfterUpdate: onAfterValueUpdateCallback, useOwnLayout: false); } else { this.control = new HermeticGUIControlClass( caption, instance, fieldInfo: fieldInfo, propertyInfo: propertyInfo, onBeforeUpdate: onBeforeValueUpdateCallback, onAfterUpdate: onAfterValueUpdateCallback); } } } } catch (Exception ex) { if (fieldInfo != null) { DebugEx.Error( "Failed to bind to field {0}.{1} => {2}: {3}", fieldInfo.DeclaringType.FullName, fieldInfo.Name, fieldInfo.FieldType, ex); } else if (propertyInfo != null) { DebugEx.Error( "Failed to bind to property {0}.{1} => {2}: {3}", propertyInfo.DeclaringType.FullName, propertyInfo.Name, propertyInfo.PropertyType, ex); } else { DebugEx.Error( "Failed to bind to method {0}.{1} => {2}: {3}", methodInfo.DeclaringType.FullName, methodInfo.Name, methodInfo.ReturnType, ex); } } }