// Used to find when decouplers fire public void onVesselStageSeparate(EventReport report) { //Debug.Log("handling separation"); Part part = report.origin; if (part.vessel.vesselType == VesselType.Debris) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("ModuleDecouple")) { ModuleDecouple md = module as ModuleDecouple; ejectionForceTotal += md.ejectionForce; } else if (module.moduleName.Contains("ModuleAnchoredDecoupler")) { ModuleAnchoredDecoupler md = module as ModuleAnchoredDecoupler; ejectionForceTotal += md.ejectionForce; } ejectionForceTotal = Mathf.Clamp(ejectionForceTotal, 0, maxDecoupleForce); } } }
public override void OnFixedUpdate() { ModuleAnchoredDecoupler DecouplerModule = (ModuleAnchoredDecoupler)part.Modules.GetModule(DecouplerModuleIndex); if (false == DecouplerModule.isDecoupled) { return; } // Debug.Log("MADFix: OnFixedUpdate, State Timer = " + StateTimer); if (0 == StateTimer) { part.vessel.angularMomentum.Zero(); part.vessel.angularVelocity.Zero(); part.rigidbody.angularVelocity.Zero(); } else if (1 == StateTimer) // Waits for struts and fuel lines to all disconnect { part.rigidbody.AddRelativeForce(Vector3d.left * EjectionForce, ForceMode.Force); Debug.Log("ModuleAnchordDecouplerFix: Fix Applied. Force = " + EjectionForce); } else if (2 == StateTimer) // Waits for the force to disappate before deleting { part.RemoveModule(this); } StateTimer++; }
public static bool IsUnfiredDecoupler(this Part p) { for (int i = 0; i < p.Modules.Count; i++) { PartModule m = p.Modules[i]; ModuleDecouple mDecouple = m as ModuleDecouple; if (mDecouple != null) { if (!mDecouple.isDecoupled) { return(true); } break; } ModuleAnchoredDecoupler mAnchoredDecoupler = m as ModuleAnchoredDecoupler; if (mAnchoredDecoupler != null) { if (!mAnchoredDecoupler.isDecoupled) { return(true); } break; } if (m.ClassName == "ProceduralFairingDecoupler") { return(true); } } return(false); }
public static bool IsUnfiredDecoupler(this Part p) { foreach (PartModule m in p.Modules) { ModuleDecouple mDecouple = m as ModuleDecouple; if (mDecouple != null) { if (!mDecouple.isDecoupled) { return(true); } break; } ModuleAnchoredDecoupler mAnchoredDecoupler = m as ModuleAnchoredDecoupler; if (mAnchoredDecoupler != null) { if (!mAnchoredDecoupler.isDecoupled) { return(true); } break; } } return(false); }
public void OnDestroy() { // Debug.LogWarning("MADFix: Destroyed."); ModuleAnchoredDecoupler DecouplerModule = (ModuleAnchoredDecoupler)part.Modules.GetModule(DecouplerModuleIndex); DecouplerModule.ejectionForce = EjectionForce; }
internal Decoupler (Part part) { this.part = part; decoupler = part.InternalPart.Module<ModuleDecouple> (); anchoredDecoupler = part.InternalPart.Module<ModuleAnchoredDecoupler> (); if (decoupler == null && anchoredDecoupler == null) throw new ArgumentException ("Part does not have a ModuleDecouple or ModuleAnchoredDecouple PartModule"); }
public void Start() { Debug.Log("MADFix: Start() against Module #" + DecouplerModuleIndex); ModuleAnchoredDecoupler DecouplerModule = (ModuleAnchoredDecoupler)part.Modules.GetModule(DecouplerModuleIndex); EjectionForce = DecouplerModule.ejectionForce; DecouplerModule.ejectionForce = 0; }
internal Decoupler(Part part) { this.part = part; decoupler = part.InternalPart.Module <ModuleDecouple> (); anchoredDecoupler = part.InternalPart.Module <ModuleAnchoredDecoupler> (); if (decoupler == null && anchoredDecoupler == null) { throw new ArgumentException("Part is not a decoupler"); } }
private void SetModuleAnchoredDecoupler() { ModuleAnchoredDecoupler decoupler = module as ModuleAnchoredDecoupler; if (decoupler == null) { return; } EjectionForce = decoupler.ejectionForce; }
private void SetModuleAnchoredDecoupler() { ModuleAnchoredDecoupler decoupler = module as ModuleAnchoredDecoupler; if (decoupler == null) { return; } EjectionForce = decoupler.ejectionForce; IsStageEnabled = decoupler.stagingEnabled; }
public override void OnUpdate() { ModuleAnchoredDecoupler DecouplerModule = (ModuleAnchoredDecoupler)part.Modules.GetModule(DecouplerModuleIndex); if (false == DecouplerModule.isDecoupled) { return; } part.vessel.angularMomentum.Zero(); part.vessel.angularVelocity.Zero(); part.rigidbody.angularVelocity.Zero(); }
/// <summary> /// Gets whether the part is a decoupler. /// </summary> static public bool IsDecoupler(this Part part) { //bool b = HasModule<ModuleDecouple>(part); ModuleDecouple md = part.FindModuleImplementing <ModuleDecouple>(); ModuleAnchoredDecoupler mad = part.FindModuleImplementing <ModuleAnchoredDecoupler>(); if (mad != null && !mad.isDecoupled) { return(true); } if (md != null && !md.isDecoupled) { return(true); } return(false); }
public static bool IsUnfiredDecoupler(this Part p) { for (int i = 0; i < p.Modules.Count; i++) { PartModule m = p.Modules[i]; ModuleDecouple mDecouple = m as ModuleDecouple; if (mDecouple != null) { if (!mDecouple.isDecoupled && p.stagingOn) { return(true); } break; } ModuleAnchoredDecoupler mAnchoredDecoupler = m as ModuleAnchoredDecoupler; if (mAnchoredDecoupler != null) { if (!mAnchoredDecoupler.isDecoupled && p.stagingOn) { return(true); } break; } ModuleDockingNode mDockingNode = m as ModuleDockingNode; if (mDockingNode != null) { if (mDockingNode.staged && mDockingNode.stagingEnabled && p.stagingOn) { return(true); } break; } if (VesselState.isLoadedProceduralFairing && m.moduleName == "ProceduralFairingDecoupler") { if (!m.Fields["decoupled"].GetValue <bool>(m) && p.stagingOn) { return(true); } break; } } return(false); }
/// <summary> /// Called when the part is started by Unity. /// </summary> public override void OnStart(StartState state) { base.OnStart(state); if (HighLogic.LoadedSceneIsFlight) { GameEvents.onStageActivate.Add(new EventData<int>.OnEvent(DetermineFailure)); decoupler = part.Modules.OfType<ModuleDecouple>().FirstOrDefault<ModuleDecouple>(); if (!decoupler) { aDecoupler = part.Modules.OfType<ModuleAnchoredDecoupler>().FirstOrDefault<ModuleAnchoredDecoupler>(); } if (decoupler) { if (failure != "") { decoupler.isDecoupled = true; } decoupler.Events["Decouple"].active = false; decoupler.Actions["DecoupleAction"].active = false; } else if (aDecoupler) { if (failure != "") { aDecoupler.isDecoupled = true; } aDecoupler.Events["Decouple"].active = false; aDecoupler.Actions["DecoupleAction"].active = false; } else { Logger.DebugError("Part \"" + part.partName + "\" contains neither a decouple or anchored decoupler module!"); return; } Fields["reliability"].guiActive = false; } }
public static bool IsUnfiredDecoupler(this Part p, out Part decoupledPart) { for (int i = 0; i < p.Modules.Count; i++) { PartModule m = p.Modules[i]; ModuleDecouple mDecouple = m as ModuleDecouple; if (mDecouple != null) { if (!mDecouple.isDecoupled && mDecouple.stagingEnabled && p.stagingOn) { decoupledPart = mDecouple.ExplosiveNode.attachedPart; if (decoupledPart == p.parent) { decoupledPart = p; } return(true); } break; } ModuleAnchoredDecoupler mAnchoredDecoupler = m as ModuleAnchoredDecoupler; if (mAnchoredDecoupler != null) { if (!mAnchoredDecoupler.isDecoupled && mAnchoredDecoupler.stagingEnabled && p.stagingOn) { decoupledPart = mAnchoredDecoupler.ExplosiveNode.attachedPart; if (decoupledPart == p.parent) { decoupledPart = p; } return(true); } break; } ModuleDockingNode mDockingNode = m as ModuleDockingNode; if (mDockingNode != null) { if (mDockingNode.staged && mDockingNode.stagingEnabled && p.stagingOn) { decoupledPart = mDockingNode.referenceNode.attachedPart; if (decoupledPart == p.parent) { decoupledPart = p; } return(true); } break; } if (VesselState.isLoadedProceduralFairing && m.moduleName == "ProceduralFairingDecoupler") { if (!m.Fields["decoupled"].GetValue <bool>(m) && p.stagingOn) { // ProceduralFairingDecoupler always decouple from their parents decoupledPart = p; return(true); } break; } } decoupledPart = null; return(false); }
private int DecoupledInStage(Part thePart) { int stage = -1; Part original = thePart; if (original.parent == null) { return(stage); //root part is always present. Fixes phantom stage if root is stageable. } List <Part> chain = new List <Part>(); //prolly dont need a list, just the previous part but whatever. while (thePart != null) { chain.Add(thePart); if (thePart.inverseStage > stage) { ModuleDecouple mdec = thePart.GetModule <ModuleDecouple>(); ModuleDockingNode mdock = thePart.GetModule <ModuleDockingNode>(); ModuleAnchoredDecoupler manch = thePart.GetModule <ModuleAnchoredDecoupler>(); if (mdec != null) { AttachNode att = thePart.FindAttachNode(mdec.explosiveNodeID); if (mdec.isOmniDecoupler) { stage = thePart.inverseStage; } else { if (att != null) { if ((thePart.parent != null && att.attachedPart == thePart.parent) || chain.Contains(att.attachedPart)) { stage = thePart.inverseStage; } } else { stage = thePart.inverseStage; } } } if (manch != null) //radial decouplers (ALSO REENTRY PODS BECAUSE REASONS!) { AttachNode att = thePart.FindAttachNode(manch.explosiveNodeID); // these stupid fuckers don't initialize in the Editor scene. if (att != null) { if ((thePart.parent != null && att.attachedPart == thePart.parent) || chain.Contains(att.attachedPart)) { stage = thePart.inverseStage; } } else { stage = thePart.inverseStage; //radial decouplers it seems the attach node ('surface') comes back null. } } if (mdock != null) //docking port { if (original == thePart) //checking self, never leaves. { } else { stage = thePart.inverseStage; } } } thePart = thePart.parent; } return(stage); }
public void computeStages() { #if DEBUG DateTime startTime = DateTime.Now; #endif double elapsedTime = 0; while (state.availableNodes.Count() > 0) { if (advancedSimulation) { state.m = state.availableNodes.Sum(p => p.Value.mass); // Compute flow for active engines foreach (EngineWrapper e in state.activeEngines) { e.evaluateFuelFlow(state.atmDensity, state.machNumber, state.throttle, false); } } else { // Compute flow for active engines, in vacuum foreach (EngineWrapper e in state.activeEngines) { e.evaluateFuelFlow(1, 1, 1, false); } } double step = Math.Max(state.availableNodes.Min(node => node.Value.getNextEvent()), 1E-100); // Quit if there is no other event if (step == Double.MaxValue && state.throttle > 0) { break; } if (advancedSimulation) { if (step > simulationStep) { step = Math.Max(simulationStep, (elapsedTime + step - stages.Last().activationTime) / 100); } if (state.throttle == 0) { step = simulationStep; } float throttle = state.throttle; var savedState = state; DState dState = RungeKutta(ref state, step); while (Math.Abs(state.throttle - throttle) > 0.05 && step > 1e-3) { state = savedState; step /= 2; dState = RungeKutta(ref state, step); } Sample sample; sample.time = elapsedTime + step; sample.velocity = state.v_surf; sample.altitude = state.r - state.planet.Radius; sample.mass = state.m; sample.acceleration = Math.Sqrt(dState.ax_nograv * dState.ax_nograv + dState.ay_nograv * dState.ay_nograv); sample.throttle = state.throttle; if (samples.Count == 0 || samples.Last().time + simulationStep <= sample.time) { samples.Add(sample); } } elapsedTime += step; // Burn the fuel ! bool eventHappens = false; foreach (Node node in state.availableNodes.Values) { eventHappens |= node.applyFuelConsumption(step); } if (!eventHappens) { continue; } // Add all decouplers in a new stage StageDescription newStage = new StageDescription(elapsedTime); foreach (Node node in state.availableNodes.Values) { ModuleDecouple decoupler = node.part.Modules.OfType <ModuleDecouple>().FirstOrDefault(); ModuleAnchoredDecoupler aDecoupler = node.part.Modules.OfType <ModuleAnchoredDecoupler>().FirstOrDefault(); if ((decoupler != null || aDecoupler != null) && !node.hasFuelInChildren(state.availableNodes)) { newStage.stageParts.Add(node.part); } } if (newStage.stageParts.Count > 0) { stages.Add(newStage); List <Part> activableChildren = new List <Part>(); // Remove all decoupled elements, fire sepratrons and parachutes foreach (Part part in newStage.stageParts) { if (state.availableNodes.ContainsKey(part)) { activableChildren.AddRange(state.availableNodes[part].getRelevantChildrenOnDecouple(state.availableNodes)); dropPartAndChildren(part); } } newStage.stageParts.AddRange(activableChildren); } // Update available engines and fuel flow List <Part> activeEngines = state.updateEngines(); if (newStage.stageParts.Count > 0) { newStage.stageParts.AddRange(activeEngines); } } // Put fairings in a separate stage before decoupling List <StageDescription> newStages = new List <StageDescription>(); for (int i = 0; i < stages.Count; i++) { var fairings = stages[i].stageParts.Where(p => p.Modules.OfType <ModuleProceduralFairing>().Count() != 0); var notfairings = stages[i].stageParts.Where(p => p.Modules.OfType <ModuleProceduralFairing>().Count() == 0); if (fairings.Count() != 0) { StageDescription fairingStage = new StageDescription(stages[i].activationTime); fairingStage.stageParts.AddRange(fairings); newStages.Add(fairingStage); } StageDescription notfairingStage = new StageDescription(stages[i].activationTime); notfairingStage.stageParts.AddRange(notfairings); newStages.Add(notfairingStage); } stages = newStages; // Put all remaining items (parachutes?) in a separate 0 stage foreach (var stage in stages) { foreach (var part in stage.stageParts) { state.availableNodes.Remove(part); } } var stage0 = new StageDescription(elapsedTime); stage0.stageParts = state.availableNodes.Keys.Where(p => p.hasStagingIcon).ToList(); if (stage0.stageParts.Count != 0) { stages.Add(stage0); } stages.Reverse(); // This is ugly, but on KSP 1.1 I have not found anything better // We call this private method for each part from the root, twice and it works... System.Reflection.MethodInfo SortIcons = null; // In KSP 1.10, an extra parameter was added to SortIcons if (Versioning.version_major == 1 && Versioning.version_minor >= 10) { SortIcons = typeof(KSP.UI.Screens.StageManager).GetMethod("SortIcons", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(bool), typeof(Part), typeof(bool), typeof(bool) }, null); } else { SortIcons = typeof(KSP.UI.Screens.StageManager).GetMethod("SortIcons", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(bool), typeof(Part), typeof(bool) }, null); } var root = stages[0].stageParts[0]; while (root.parent != null) { root = root.parent; } setStages(root, SortIcons); // setStages(root, SortIcons); #if DEBUG var compTime = DateTime.Now - startTime; Debug.Log("Staging computed in " + compTime.TotalMilliseconds + "ms"); if (samples.Count() > 0) { string result = "time;altitude;velocity;acceleration;mass;throttle\n"; foreach (var sample in samples) { result += sample.time + ";" + sample.altitude + ";" + sample.velocity + ";" + sample.acceleration + ";" + sample.mass + ";" + sample.throttle + "\n"; } Debug.Log(result); } #endif }
public static bool IsUnfiredDecoupler(this Part p) { bool isFairing = false; for (int i = 0; i < p.Modules.Count; i++) { PartModule m = p.Modules[i]; ModuleDecouple mDecouple = m as ModuleDecouple; if (mDecouple != null) { if (!mDecouple.isDecoupled && mDecouple.stagingEnabled && p.stagingOn) { return(true); } break; } ModuleAnchoredDecoupler mAnchoredDecoupler = m as ModuleAnchoredDecoupler; if (mAnchoredDecoupler != null) { if (!mAnchoredDecoupler.isDecoupled && mAnchoredDecoupler.stagingEnabled && p.stagingOn) { return(true); } break; } ModuleDockingNode mDockingNode = m as ModuleDockingNode; if (mDockingNode != null) { if (mDockingNode.staged && mDockingNode.stagingEnabled && p.stagingOn) { return(true); } break; } if (m is ModuleProceduralFairing) { isFairing = true; } if (isFairing) { if (VesselState.isLoadedFAR && m.stagingEnabled && p.stagingOn) { return(true); } else if (m is ModuleCargoBay) { ModuleCargoBay fairing = m as ModuleCargoBay; if (fairing.ClosedAndLocked() && m.stagingEnabled && p.stagingOn) { return(true); } break; } } if (VesselState.isLoadedProceduralFairing && m.moduleName == "ProceduralFairingDecoupler") { if (!m.Fields["decoupled"].GetValue <bool>(m) && m.stagingEnabled && p.stagingOn) { return(true); } break; } } return(false); }
private int DecoupledInStage(Part thePart) { int stage = -1; Part original = thePart; while (thePart != null) { if (thePart.inverseStage > stage) { ModuleDecouple mdec = thePart.GetModule <ModuleDecouple>(); ModuleDockingNode mdock = thePart.GetModule <ModuleDockingNode>(); ModuleAnchoredDecoupler manch = thePart.GetModule <ModuleAnchoredDecoupler>(); if (mdec != null) { ModuleDynamicNodes mdyn = thePart.GetModule <ModuleDynamicNodes>(); if (mdyn != null) { //engine plate if (original == thePart) { //checking self, make sure not upside down if (thePart.FindAttachNodeByPart(thePart.parent).id == "bottom") //leaves with stage { stage = thePart.inverseStage; } } else if (original.parent != null && original.parent == thePart) { //plate direct child. if (thePart.FindAttachNodeByPart(original).id == "bottom") { stage = thePart.inverseStage; //goodbye! } } else { stage = thePart.inverseStage; //decouple. } } else { //regular decoupler if (original == thePart) { //checking self if (mdec.isOmniDecoupler || thePart.FindAttachNodeByPart(thePart.parent).id == "top") //leaves with stage { stage = thePart.inverseStage; } } else { stage = thePart.inverseStage; } } } if (manch != null) //radial decouple { if (original == thePart) { //checking self if (thePart.FindAttachNodeByPart(thePart.parent).id == "top") //leaves with stage { stage = thePart.inverseStage; } } else { stage = thePart.inverseStage; } } if (mdock != null) //docking port { if (original == thePart) { //checking self, never leaves. } else { stage = thePart.inverseStage; } } } thePart = thePart.parent; } return(stage); }
/// <summary> /// Creates an DecouplerManager for a part. /// Allows unified control of a ModuleDecouple/ModulenchoredDecoupler. /// </summary> public DecouplerManager(Part p) { this.decoupler = p.Modules.OfType <ModuleDecouple>().FirstOrDefault(); this.aDecoupler = p.Modules.OfType <ModuleAnchoredDecoupler>().FirstOrDefault(); this.isDecoupler = this.decoupler != null; }
// Determine when this part will be decoupled given when its parent will be decoupled. // Then recurse to all of this part's children. public void AssignDecoupledInStage(Part p, Dictionary <Part, FuelNode> nodeLookup, int parentDecoupledInStage) { // Already processed if (decoupledInStage != int.MinValue) { return; } bool isDecoupler = false; decoupledInStage = parentDecoupledInStage; for (int i = 0; i < p.Modules.Count; i++) { PartModule m = p.Modules[i]; ModuleDecouple mDecouple = m as ModuleDecouple; if (mDecouple != null) { if (!mDecouple.isDecoupled && mDecouple.stagingEnabled && p.stagingOn) { if (mDecouple.isOmniDecoupler) { isDecoupler = true; // We are decoupling our parent // The part and its children are not part of the ship when we decouple decoupledInStage = p.inverseStage; // The parent should already have its info assigned at this point //nodeLookup[p.parent].AssignDecoupledInStage(p.parent, nodeLookup, p.inverseStage); // The part children are decoupled when we decouple foreach (Part child in p.children) { nodeLookup[child].AssignDecoupledInStage(child, nodeLookup, p.inverseStage); } } else { AttachNode attach; if (mDecouple.explosiveNodeID != "srf") { attach = p.FindAttachNode(mDecouple.explosiveNodeID); } else { attach = p.srfAttachNode; } if (attach != null && attach.attachedPart != null) { if (attach.attachedPart == p.parent) { isDecoupler = true; // We are decoupling our parent // The part and its children are not part of the ship when we decouple decoupledInStage = p.inverseStage; //print("AssignDecoupledInStage ModuleDecouple " + p.partInfo.name + "(" + p.inverseStage + ") decoupling " + attach.attachedPart + "(" + attach.attachedPart.inverseStage + "). parent " + decoupledInStage); // The parent should already have its info assigned at this point //nodeLookup[p.parent].AssignDecoupledInStage(p.parent, nodeLookup, p.inverseStage); } else { isDecoupler = true; // We are still attached to our parent // The part and it's children are dropped when the parent is decoupledInStage = parentDecoupledInStage; //print("AssignDecoupledInStage ModuleDecouple " + p.partInfo.name + "(" + p.inverseStage + ") decoupling " + attach.attachedPart + "(" + attach.attachedPart.inverseStage + "). not the parent " + decoupledInStage); // The part we decouple is dropped when we decouple nodeLookup[attach.attachedPart].AssignDecoupledInStage(attach.attachedPart, nodeLookup, p.inverseStage); } } } break; // Hopefully no one made part with multiple decoupler modules ? } } ModuleAnchoredDecoupler mAnchoredDecoupler = m as ModuleAnchoredDecoupler; if (mAnchoredDecoupler != null) { if (!mAnchoredDecoupler.isDecoupled && mAnchoredDecoupler.stagingEnabled && p.stagingOn) { AttachNode attach; if (mAnchoredDecoupler.explosiveNodeID != "srf") { attach = p.FindAttachNode(mAnchoredDecoupler.explosiveNodeID); } else { attach = p.srfAttachNode; } if (attach != null && attach.attachedPart != null) { if (attach.attachedPart == p.parent) { isDecoupler = true; // We are decoupling our parent // The part and its children are not part of the ship when we decouple decoupledInStage = p.inverseStage; //print("AssignDecoupledInStage ModuleAnchoredDecoupler " + p.partInfo.name + "(" + p.inverseStage + ") decoupling " + attach.attachedPart + "(" + attach.attachedPart.inverseStage + "). parent " + decoupledInStage); // The parent should already have its info assigned at this point //nodeLookup[p.parent].AssignDecoupledInStage(p.parent, nodeLookup, p.inverseStage); } else { isDecoupler = true; // We are still attached to our parent // The part and it's children are dropped when the parent is decoupledInStage = parentDecoupledInStage; //print("AssignDecoupledInStage ModuleAnchoredDecoupler " + p.partInfo.name + "(" + p.inverseStage + ") decoupling " + attach.attachedPart + "(" + attach.attachedPart.inverseStage + "). not the parent " + decoupledInStage); // The part we decouple is dropped when we decouple nodeLookup[attach.attachedPart].AssignDecoupledInStage(attach.attachedPart, nodeLookup, p.inverseStage); } } break; } } ModuleDockingNode mDockingNode = m as ModuleDockingNode; if (mDockingNode != null) { if (mDockingNode.staged && mDockingNode.stagingEnabled && p.stagingOn) { Part attachedPart = mDockingNode.referenceNode.attachedPart; if (attachedPart != null) { if (attachedPart == p.parent) { isDecoupler = true; // We are decoupling our parent // The part and its children are not part of the ship when we decouple decoupledInStage = p.inverseStage; // The parent should already have its info assigned at this point //nodeLookup[p.parent].AssignDecoupledInStage(p.parent, nodeLookup, p.inverseStage); } else { isDecoupler = true; decoupledInStage = parentDecoupledInStage; //childDecoupledInStage = parentDecoupledInStage; nodeLookup[attachedPart].AssignDecoupledInStage(attachedPart, nodeLookup, p.inverseStage); } } } break; } if (m.moduleName == "ProceduralFairingDecoupler") { if (!m.Fields["decoupled"].GetValue <bool>(m) && m.stagingEnabled && p.stagingOn) { isDecoupler = true; // We are decoupling our parent // The part and its children are not part of the ship when we decouple decoupledInStage = p.inverseStage; break; } } } if (p.IsLaunchClamp()) { decoupledInStage = p.inverseStage > parentDecoupledInStage ? p.inverseStage : parentDecoupledInStage; //print("AssignDecoupledInStage D " + p.partInfo.name + " " + parentDecoupledInStage); } else if (!isDecoupler) { decoupledInStage = parentDecoupledInStage; //print("AssignDecoupledInStage " + p.partInfo.name + "(" + p.inverseStage + ")" + decoupledInStage); } isSepratron = isEngine && (inverseStage == decoupledInStage); for (int i = 0; i < p.children.Count; i++) { Part child = p.children[i]; nodeLookup[child].AssignDecoupledInStage(child, nodeLookup, decoupledInStage); } }
public void computeStages() { #if DEBUG DateTime startTime = DateTime.Now; #endif double elapsedTime = 0; while (state.availableNodes.Count() > 0) { if (advancedSimulation) { state.m = state.availableNodes.Sum(p => p.Value.mass); // Compute flow for active engines foreach (EngineWrapper e in state.activeEngines) { e.evaluateFuelFlow(state.atmDensity, state.machNumber, state.throttle, false); } } else { // Compute flow for active engines, in vacuum foreach (EngineWrapper e in state.activeEngines) { e.evaluateFuelFlow(1, 1, 1, false); } } double step = Math.Max(state.availableNodes.Min(node => node.Value.getNextEvent()), 1E-100); // Quit if there is no other event if (step == Double.MaxValue && state.throttle > 0) { break; } if (advancedSimulation) { if (step > simulationStep) { step = Math.Max(simulationStep, (elapsedTime + step - stages.Last().activationTime) / 100); } if (state.throttle == 0) { step = simulationStep; } float throttle = state.throttle; var savedState = state; DState dState = RungeKutta(ref state, step); while (Math.Abs(state.throttle - throttle) > 0.05 && step > 1e-3) { state = savedState; step /= 2; dState = RungeKutta(ref state, step); } Sample sample; sample.time = elapsedTime + step; sample.velocity = state.v_surf; sample.altitude = state.r - state.planet.Radius; sample.mass = state.m; sample.acceleration = Math.Sqrt(dState.ax_nograv * dState.ax_nograv + dState.ay_nograv * dState.ay_nograv); sample.throttle = state.throttle; if (samples.Count == 0 || samples.Last().time + simulationStep <= sample.time) { samples.Add(sample); } } elapsedTime += step; // Burn the fuel ! bool eventHappens = false; foreach (Node node in state.availableNodes.Values) { eventHappens |= node.applyFuelConsumption(step); } if (!eventHappens) { continue; } // Add all decouplers in a new stage StageDescription dpStage = new StageDescription(elapsedTime); foreach (Node node in state.availableNodes.Values) { ModuleDecouple decoupler = node.part.Modules.OfType <ModuleDecouple>().FirstOrDefault(); ModuleAnchoredDecoupler aDecoupler = node.part.Modules.OfType <ModuleAnchoredDecoupler>().FirstOrDefault(); if ((decoupler != null || aDecoupler != null) && !node.hasFuelInChildren(state.availableNodes)) { dpStage.stageParts.Add(node.part); } } if (dpStage.stageParts.Count > 0) { stages.Add(dpStage); List <Part> activableChildren = new List <Part>(); // Remove all decoupled elements, fire sepratrons and parachutes foreach (Part part in dpStage.stageParts) { if (state.availableNodes.ContainsKey(part)) { activableChildren.AddRange(state.availableNodes[part].getRelevantChildrenOnDecouple(state.availableNodes)); dropPartAndChildren(part); } } dpStage.stageParts.AddRange(activableChildren); } // Update available engines and fuel flow List <Part> activeEngines = state.updateEngines(); StageDescription newStage = new StageDescription(elapsedTime); newStage.stageParts.AddRange(activeEngines); stages.Add(newStage); } // Put all remaining items (parachutes?) in a separate 0 stage foreach (var stage in stages) { foreach (var part in stage.stageParts) { state.availableNodes.Remove(part); } } // Put fairings in a separate stage before decoupling List <StageDescription> newStages = new List <StageDescription>(); for (int i = 0; i < stages.Count; i++) { var fairings = stages[i].stageParts.Where(p => p.Modules.OfType <ModuleProceduralFairing>().Count() != 0); var notfairings = stages[i].stageParts.Where(p => p.Modules.OfType <ModuleProceduralFairing>().Count() == 0); if (fairings.Count() != 0) { StageDescription fairingStage = new StageDescription(stages[i].activationTime); fairingStage.stageParts.AddRange(fairings); newStages.Add(fairingStage); } StageDescription notfairingStage = new StageDescription(stages[i].activationTime); notfairingStage.stageParts.AddRange(notfairings); newStages.Add(notfairingStage); } stages = newStages; int initialStage = 0; foreach (Part part in state.availableNodes.Keys) { if (part.hasStagingIcon) { part.inverseStage = 0; initialStage = 1; } } // doesn't seem to work in 1.1 // Set stage number correctly //StageManager.SetStageCount (stages.Count); for (int stage = stages.Count - 1; stage >= 0; stage--) { var currentStage = stages[stage]; foreach (Part part in currentStage.stageParts) { part.inverseStage = stages.Count - 1 - stage + initialStage; } } // doesn't seem to work in 1.1 //StageManager.Instance.SortIcons (true); #if DEBUG var compTime = DateTime.Now - startTime; Debug.Log("Staging computed in " + compTime.TotalMilliseconds + "ms"); if (samples.Count() > 0) { string result = "time;altitude;velocity;acceleration;mass;throttle\n"; foreach (var sample in samples) { result += sample.time + ";" + sample.altitude + ";" + sample.velocity + ";" + sample.acceleration + ";" + sample.mass + ";" + sample.throttle + "\n"; } Debug.Log(result); } #endif }