/// <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); } } }
// Resets item state when joint is broken. // A callback from MonoBehaviour. void OnJointBreak(float breakForce) { if (staticAttached) { Logger.logWarning("A static joint has just been broken! Force: {0}", breakForce); } else { Logger.logWarning("A fixed joint has just been broken! Force: {0}", breakForce); } GroundDetach(); }
public static void CouplePart(Part srcPart, Part tgtPart, string srcAttachNodeID = null, AttachNode tgtAttachNode = null) { // Node links if (srcAttachNodeID != null) { if (srcAttachNodeID == "srfAttach") { Logger.logInfo("Attach type: {0} | ID : {1}", srcPart.srfAttachNode.nodeType, srcPart.srfAttachNode.id); srcPart.attachMode = AttachModes.SRF_ATTACH; srcPart.srfAttachNode.attachedPart = tgtPart; } else { AttachNode srcAttachNode = srcPart.FindAttachNode(srcAttachNodeID); if (srcAttachNode != null) { Logger.logInfo("Attach type : {0} | ID : {1}", srcPart.srfAttachNode.nodeType, srcAttachNode.id); srcPart.attachMode = AttachModes.STACK; srcAttachNode.attachedPart = tgtPart; if (tgtAttachNode != null) { tgtAttachNode.attachedPart = srcPart; } else { Logger.logWarning("Target node is null"); } } else { Logger.logError("Source attach node not found !"); } } } else { Logger.logWarning("Missing source attach node !"); } srcPart.Couple(tgtPart); }
/// <summary>Decouples <paramref name="assemblyRoot"/> from the vessel.</summary> /// <remarks>Also does external links cleanup on both vessels.</remarks> /// <param name="assemblyRoot">An assembly to decouple.</param> public static void DecoupleAssembly(Part assemblyRoot) { if (!assemblyRoot.parent) { return; // Nothing to decouple. } SendKISMessage(assemblyRoot, MessageAction.Decouple); Vessel oldVessel = assemblyRoot.vessel; var formerParent = assemblyRoot.parent; assemblyRoot.decouple(); // HACK: As of KSP 1.0.5 some parts (e.g docking ports) can be attached by both a // surface node and by a stack node which looks like an editor bug in some corner case. // In this case decouple() will only clear the surface node leaving the stack one // refering the parent. This misconfiguration will badly affect all further KIS // operations on the part. Do a cleanup job here to workaround this bug. var orphanNode = assemblyRoot.FindAttachNodeByPart(formerParent); if (orphanNode != null) { Logger.logWarning("KSP BUG: Cleanup orphan node {0} in the assembly", orphanNode.id); orphanNode.attachedPart = null; // Also, check that parent is properly cleaned up. var parentOrphanNode = formerParent.FindAttachNodeByPart(assemblyRoot); if (parentOrphanNode != null) { Logger.logWarning("KSP BUG: Cleanup orphan node {0} in the parent", parentOrphanNode.id); parentOrphanNode.attachedPart = null; } } CleanupExternalLinks(oldVessel); CleanupExternalLinks(assemblyRoot.vessel); RenameAssemblyVessel(assemblyRoot); }