private void SetGeneratorInfo() { var moduleGenerator = PartExtensions.GetModule <ModuleGenerator>(selectedPart); if (moduleGenerator != null) { if (moduleGenerator.resHandler.inputResources.Count > 0) { infoItems.Add(PartInfoItem.Create("Generator Input")); for (int i = 0; i < moduleGenerator.resHandler.inputResources.Count; ++i) { var generatorResource = moduleGenerator.resHandler.inputResources[i]; infoItems.Add(PartInfoItem.Create("\t" + generatorResource.name, generatorResource.rate.ToRate())); } } if (moduleGenerator.resHandler.outputResources.Count > 0) { infoItems.Add(PartInfoItem.Create("Generator Output")); for (int i = 0; i < moduleGenerator.resHandler.outputResources.Count; ++i) { var generatorResource = moduleGenerator.resHandler.outputResources[i]; infoItems.Add(PartInfoItem.Create("\t" + generatorResource.name, generatorResource.rate.ToRate())); } } if (moduleGenerator.isAlwaysActive) { infoItems.Add(PartInfoItem.Create("Generator is Always Active")); } } }
private void SetSasInfo() { if (PartExtensions.HasModule <ModuleSAS>(selectedPart)) { infoItems.Add(PartInfoItem.Create("SAS Equiped")); } }
private void SetEngineInfo() { var protoModuleEngine = PartExtensions.GetProtoModuleEngine(selectedPart); if (protoModuleEngine != null) { infoItems.Add(PartInfoItem.Create("Thrust", Units.ToForce(protoModuleEngine.MinimumThrust, protoModuleEngine.MaximumThrust))); infoItems.Add(PartInfoItem.Create("Isp", Units.ConcatF(protoModuleEngine.GetSpecificImpulse(1.0f), protoModuleEngine.GetSpecificImpulse(0.0f)) + "s")); if (protoModuleEngine.Propellants.Count > 0) { infoItems.Add(PartInfoItem.Create("Propellants")); float totalRatio = 0.0f; for (int i = 0; i < protoModuleEngine.Propellants.Count; ++i) { totalRatio = totalRatio + protoModuleEngine.Propellants[i].ratio; } for (int i = 0; i < protoModuleEngine.Propellants.Count; ++i) { var propellant = protoModuleEngine.Propellants[i]; infoItems.Add(PartInfoItem.Create("\t" + propellant.name, (propellant.ratio / totalRatio).ToPercent())); } } } }
private void SetScienceContainerInfo() { if (PartExtensions.HasModule <ModuleScienceContainer>(selectedPart)) { infoItems.Add(PartInfoItem.Create("Science Container")); } }
private void SetSingleActivationInfo() { if (PartExtensions.HasModule <ModuleAnimateGeneric>(selectedPart, m => m.isOneShot)) { infoItems.Add(PartInfoItem.Create("Single Activation")); } }
private void SetMassItems() { if (selectedPart.physicalSignificance == Part.PhysicalSignificance.FULL) { infoItems.Add(PartInfoItem.Create("Mass", Units.ToMass(PartExtensions.GetDryMass(selectedPart), PartExtensions.GetWetMass(selectedPart)))); } }
private void SetGimbalInfo() { var moduleGimbal = PartExtensions.GetModule <ModuleGimbal>(selectedPart); if (moduleGimbal != null) { infoItems.Add(PartInfoItem.Create("Thrust Vectoring", moduleGimbal.gimbalRange.ToString("F2"))); } }
private void SetRcsInfo() { var moduleRcs = PartExtensions.GetModule <ModuleRCS>(selectedPart); if (moduleRcs != null) { infoItems.Add(PartInfoItem.Create("Thruster Power", moduleRcs.thrusterPower.ToForce())); infoItems.Add(PartInfoItem.Create("Specific Impulse", Units.ConcatF(moduleRcs.atmosphereCurve.Evaluate(1.0f), moduleRcs.atmosphereCurve.Evaluate(0.0f)) + "s")); } }
private void SetParachuteInfo() { var moduleParachute = PartExtensions.GetModule <ModuleParachute>(selectedPart); if (moduleParachute != null) { infoItems.Add(PartInfoItem.Create("Deployed Drag", Units.ConcatF(moduleParachute.semiDeployedDrag, moduleParachute.fullyDeployedDrag))); infoItems.Add(PartInfoItem.Create("Deployment Altitude", moduleParachute.deployAltitude.ToDistance())); infoItems.Add(PartInfoItem.Create("Deployment Pressure", moduleParachute.minAirPressureToOpen.ToString("F2"))); } }
private void SetDecouplerInfo() { var protoModuleDecoupler = PartExtensions.GetProtoModuleDecoupler(selectedPart); if (protoModuleDecoupler != null) { infoItems.Add(PartInfoItem.Create("Ejection Force", protoModuleDecoupler.EjectionForce.ToForce())); if (protoModuleDecoupler.IsOmniDecoupler) { infoItems.Add(PartInfoItem.Create("Omni-directional")); } } }
private void SetTransmitterInfo() { var moduleDataTransmitter = PartExtensions.GetModule <ModuleDataTransmitter>(selectedPart); if (moduleDataTransmitter != null) { infoItems.Add(PartInfoItem.Create("Packet Size", moduleDataTransmitter.packetSize.ToString("F2") + " Mits")); infoItems.Add(PartInfoItem.Create("Bandwidth", (moduleDataTransmitter.packetInterval * moduleDataTransmitter.packetSize).ToString("F2") + "Mits/sec")); // TODO: allow for multiple consumed resources infoItems.Add(PartInfoItem.Create(moduleDataTransmitter.GetConsumedResources()[0].name, moduleDataTransmitter.packetResourceCost.ToString("F2") + "/Packet")); } }
private void SetAlternatorInfo() { ModuleAlternator moduleAlternator = PartExtensions.GetModule <ModuleAlternator>(selectedPart); if (moduleAlternator != null) { infoItems.Add(PartInfoItem.Create("Alternator")); for (int i = 0; i < moduleAlternator.resHandler.outputResources.Count; ++i) { var moduleResource = moduleAlternator.resHandler.outputResources[i]; infoItems.Add(PartInfoItem.Create("\t" + moduleResource.name, moduleResource.rate.ToRate())); } } }
private void SetScienceExperimentInfo() { var moduleScienceExperiment = PartExtensions.GetModule <ModuleScienceExperiment>(selectedPart); if (moduleScienceExperiment != null) { infoItems.Add(PartInfoItem.Create("Science Experiment", moduleScienceExperiment.experimentActionName)); infoItems.Add(PartInfoItem.Create("\tTransmit Efficiency", moduleScienceExperiment.xmitDataScalar.ToPercent())); if (moduleScienceExperiment.rerunnable == false) { infoItems.Add(PartInfoItem.Create("\tSingle Usage")); } } }
private static bool IsEnginePlate(Part thePart) { ModuleDecouple mdec = PartExtensions.GetModule <ModuleDecouple>(thePart); if (mdec != null && mdec.IsStageable()) { ModuleDynamicNodes mdyn = PartExtensions.GetModule <ModuleDynamicNodes>(thePart); if (mdyn != null) { return(true); } } return(false); }
private void SetReactionWheelInfo() { var moduleReactionWheel = PartExtensions.GetModule <ModuleReactionWheel>(selectedPart); if (moduleReactionWheel != null) { infoItems.Add(PartInfoItem.Create("Reaction Wheel Torque")); infoItems.Add(PartInfoItem.Create("\tPitch", moduleReactionWheel.PitchTorque.ToTorque())); infoItems.Add(PartInfoItem.Create("\tRoll", moduleReactionWheel.RollTorque.ToTorque())); infoItems.Add(PartInfoItem.Create("\tYaw", moduleReactionWheel.YawTorque.ToTorque())); for (int i = 0; i < moduleReactionWheel.resHandler.inputResources.Count; ++i) { var moduleResource = moduleReactionWheel.resHandler.inputResources[i]; infoItems.Add(PartInfoItem.Create("\t" + moduleResource.name, moduleResource.rate.ToRate())); } } }
private void SetSolarPanelInfo() { var moduleDeployableSolarPanel = PartExtensions.GetModule <ModuleDeployableSolarPanel>(selectedPart); if (moduleDeployableSolarPanel != null) { infoItems.Add(PartInfoItem.Create("Charge Rate", moduleDeployableSolarPanel.chargeRate.ToRate())); if (moduleDeployableSolarPanel.isBreakable) { infoItems.Add(PartInfoItem.Create("Breakable")); } if (moduleDeployableSolarPanel.trackingBody == Sun.Instance) { infoItems.Add(PartInfoItem.Create("Sun Tracking")); } } }
/// <summary> /// Updates the details by recalculating if requested. /// </summary> public void Update() { try { if (!this.hasCheckedAeroMods) { this.CheckAeroMods(); } if (FlightGlobals.ActiveVessel.atmDensity < double.Epsilon || NearInstalled) { ShowDetails = false; return; } ShowDetails = true; if (FarInstalled) { TerminalVelocity = (double)this.farTerminalVelocity.Invoke(null, null); } else { var m = FlightGlobals.ActiveVessel.parts.Sum(part => PartExtensions.GetWetMass(part)) * 1000.0; var g = FlightGlobals.getGeeForceAtPosition(FlightGlobals.ship_position).magnitude; var a = FlightGlobals.ActiveVessel.parts.Sum(part => part.DragCubes.AreaDrag) * PhysicsGlobals.DragCubeMultiplier; var p = FlightGlobals.ActiveVessel.atmDensity; var c = PhysicsGlobals.DragMultiplier; TerminalVelocity = Math.Sqrt((2.0 * m * g) / (p * a * c)); StaticPressure = FlightGlobals.ActiveVessel.staticPressurekPa; DynamicPressure = FlightGlobals.ActiveVessel.dynamicPressurekPa; } Efficiency = FlightGlobals.ship_srfSpeed / TerminalVelocity; } catch (Exception ex) { MyLogger.Exception(ex, "AtmosphericProcessor->Update"); } }
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. } chain.Clear(); while (thePart != null) { chain.Add(thePart); if (thePart.inverseStage > stage) { ModuleDecouple mdec = PartExtensions.GetModule <ModuleDecouple>(thePart); ModuleDockingNode mdock = PartExtensions.GetModule <ModuleDockingNode>(thePart); ModuleAnchoredDecoupler manch = PartExtensions.GetModule <ModuleAnchoredDecoupler>(thePart); 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) || PartExtensions.ContainedPart(att.attachedPart, chain)) { 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) || PartExtensions.ContainedPart(att.attachedPart, chain)) { 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); }
// This function prepares the simulation by creating all the necessary data structures it will // need during the simulation. All required data is copied from the core game data structures // so that the simulation itself can be run in a background thread without having issues with // the core game changing the data while the simulation is running. public bool PrepareSimulation(LogMsg _log, List <Part> parts, double theGravity, double theAtmosphere = 0, double theMach = 0, bool dumpTree = false, bool vectoredThrust = false, bool fullThrust = false) { log = _log; if (log != null) { log.AppendLine("PrepareSimulation started"); } _timer.Reset(); _timer.Start(); // Store the parameters in members for ease of access in other functions partList = parts; gravity = theGravity; atmosphere = theAtmosphere; mach = theMach; lastStage = StageManager.LastStage; maxMach = 1.0f; if (log != null) { log.AppendLine("lastStage = ", lastStage); } // Clear the lists for our simulation parts allParts.Clear(); allFuelLines.Clear(); drainingParts.Clear(); allEngines.Clear(); activeEngines.Clear(); drainingResources.Clear(); // A dictionary for fast lookup of Part->PartSim during the preparation phase partSimLookup.Clear(); if (partList.Count > 0 && partList[0].vessel != null) { vesselName = partList[0].vessel.vesselName; vesselType = partList[0].vessel.vesselType; } // First we create a PartSim for each Part (giving each a unique id) int partId = 1; for (int i = 0; i < partList.Count; ++i) { Part part = partList[i]; // If the part is already in the lookup dictionary then log it and skip to the next part if (partSimLookup.ContainsKey(part)) { if (log != null) { log.AppendLine("Part ", part.name, " appears in vessel list more than once"); } continue; } // Create the PartSim PartSim partSim = PartSim.New(part, partId, atmosphere, log); // Add it to the Part lookup dictionary and the necessary lists partSimLookup.Add(part, partSim); allParts.Add(partSim); if (partSim.isFuelLine) { allFuelLines.Add(partSim); } if (partSim.isEngine) { partSim.CreateEngineSims(allEngines, atmosphere, mach, vectoredThrust, fullThrust, log); } if (partSim.isRCS) { partSim.CreateRCSSims(allRCS, atmosphere, mach, vectoredThrust, fullThrust, log); } partId++; } for (int i = 0; i < allEngines.Count; ++i) { maxMach = Mathf.Max(maxMach, allEngines[i].maxMach); } UpdateActiveEngines(); // Now that all the PartSims have been created we can do any set up that needs access to other parts // First we set up all the parent links for (int i = 0; i < allParts.Count; i++) { PartSim partSim = allParts[i]; partSim.SetupParent(partSimLookup, log); } // Then, in the VAB/SPH, we add the parent of each fuel line to the fuelTargets list of their targets if (HighLogic.LoadedSceneIsEditor) { for (int i = 0; i < allFuelLines.Count; ++i) { PartSim partSim = allFuelLines[i]; CModuleFuelLine fuelLine = PartExtensions.GetModule <CModuleFuelLine>(partSim.part); if (fuelLine.target != null) { PartSim targetSim; if (partSimLookup.TryGetValue(fuelLine.target, out targetSim)) { if (log != null) { log.AppendLine("Fuel line target is ", targetSim.name, ":", targetSim.partId); } targetSim.fuelTargets.Add(partSim.parent); } else { if (log != null) { log.AppendLine("No PartSim for fuel line target (", partSim.part.partInfo.name, ")"); } } } else { if (log != null) { log.AppendLine("Fuel line target is null"); } } } } if (log != null) { log.AppendLine("SetupAttachNodes and count stages"); } for (int i = 0; i < allParts.Count; ++i) { PartSim partSim = allParts[i]; partSim.SetupAttachNodes(partSimLookup, log); if (partSim.decoupledInStage >= lastStage) { lastStage = partSim.decoupledInStage + 1; } } // And finally release the Part references from all the PartSims if (log != null) { log.AppendLine("ReleaseParts"); } for (int i = 0; i < allParts.Count; ++i) { allParts[i].ReleasePart(); } // And dereference the core's part list partList = null; _timer.Stop(); if (log != null) { log.AppendLine("PrepareSimulation: ", _timer.ElapsedMilliseconds, "ms"); log.Flush(); } Dump(); log = null; return(true); }
private void SetCostInfo() { infoItems.Add(PartInfoItem.Create("Cost", Units.ConcatF(PartExtensions.GetCostDry(selectedPart), PartExtensions.GetCostWet(selectedPart)))); }
public static PartSim New(Part p, int id, double atmosphere, LogMsg log) { PartSim partSim = pool.Borrow(); partSim.part = p; partSim.centerOfMass = p.transform.TransformPoint(p.CoMOffset); partSim.partId = id; partSim.name = p.partInfo.name; if (log != null) { log.AppendLine("Create PartSim for ", partSim.name); } partSim.parent = null; partSim.parentAttach = p.attachMode; partSim.fuelCrossFeed = p.fuelCrossFeed; partSim.noCrossFeedNodeKey = p.NoCrossFeedNodeKey; partSim.isEnginePlate = IsEnginePlate(p); if (partSim.isEnginePlate) { partSim.noCrossFeedNodeKey = "bottom"; //sadly this only works in one direction. } partSim.decoupledInStage = partSim.DecoupledInStage(p); partSim.isFuelLine = PartExtensions.HasModule <CModuleFuelLine>(p); partSim.isRCS = PartExtensions.HasModule <ModuleRCS>(p) || PartExtensions.HasModule <ModuleRCSFX>(p); //I don't think it checks inheritance. partSim.isSepratron = PartExtensions.IsSepratron(p); partSim.inverseStage = p.inverseStage; if (log != null) { log.AppendLine("inverseStage = ", partSim.inverseStage); } partSim.resPriorityOffset = p.resourcePriorityOffset; partSim.resPriorityUseParentInverseStage = p.resourcePriorityUseParentInverseStage; partSim.resRequestRemainingThreshold = p.resourceRequestRemainingThreshold; partSim.baseCost = PartExtensions.GetCostDry(p); if (log != null) { log.AppendLine("Parent part = ", (p.parent == null ? "null" : p.parent.partInfo.name)) .AppendLine("physicalSignificance = ", p.physicalSignificance) .AppendLine("PhysicsSignificance = ", p.PhysicsSignificance); } // Work out if the part should have no physical significance // The root part is never "no physics" partSim.isNoPhysics = p.physicalSignificance == Part.PhysicalSignificance.NONE || p.PhysicsSignificance == 1; if (PartExtensions.HasModule <LaunchClamp>(p)) { partSim.realMass = 0d; if (log != null) { log.AppendLine("Ignoring mass of launch clamp"); } } else { partSim.crewMassOffset = PartExtensions.getCrewAdjustment(p); partSim.realMass = p.mass + partSim.crewMassOffset; if (log != null) { log.AppendLine("Using part.mass of " + partSim.realMass); } } partSim.postStageMassAdjust = 0f; if (log != null) { log.AppendLine("Calculating postStageMassAdjust, prefabMass = ", p.prefabMass); } int count = p.Modules.Count; for (int i = 0; i < count; i++) { if (log != null) { log.AppendLine("Module: ", p.Modules[i].moduleName); } IPartMassModifier partMassModifier = p.Modules[i] as IPartMassModifier; if (partMassModifier != null) { if (log != null) { log.AppendLine("ChangeWhen = ", partMassModifier.GetModuleMassChangeWhen()); } if (partMassModifier.GetModuleMassChangeWhen() == ModifierChangeWhen.STAGED) { float preStage = partMassModifier.GetModuleMass(p.prefabMass, ModifierStagingSituation.UNSTAGED); float postStage = partMassModifier.GetModuleMass(p.prefabMass, ModifierStagingSituation.STAGED); if (log != null) { log.AppendLine("preStage = ", preStage, " postStage = ", postStage); } partSim.postStageMassAdjust += (postStage - preStage); } } } if (log != null) { log.AppendLine("postStageMassAdjust = ", partSim.postStageMassAdjust); } if (log != null) { log.AppendLine("crewMassOffset = ", partSim.crewMassOffset); } for (int i = 0; i < p.Resources.Count; i++) { PartResource resource = p.Resources[i]; // Make sure it isn't NaN as this messes up the part mass and hence most of the values // This can happen if a resource capacity is 0 and tweakable if (!Double.IsNaN(resource.amount)) { if (log != null) { log.AppendLine(resource.resourceName, " = ", resource.amount); } partSim.resources.Add(resource.info.id, resource.amount); partSim.resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0); } else { if (log != null) { log.AppendLine(resource.resourceName, " is NaN. Skipping."); } } } partSim.hasVessel = (p.vessel != null); partSim.isLanded = partSim.hasVessel && p.vessel.Landed; if (partSim.hasVessel) { partSim.vesselName = p.vessel.vesselName; partSim.vesselType = p.vesselType; } partSim.initialVesselName = p.initialVesselName; partSim.hasMultiModeEngine = PartExtensions.HasModule <MultiModeEngine>(p); partSim.hasModuleEngines = PartExtensions.HasModule <ModuleEngines>(p); partSim.isEngine = partSim.hasMultiModeEngine || partSim.hasModuleEngines; if (log != null) { log.AppendLine("Created ", partSim.name, ". Decoupled in stage ", partSim.decoupledInStage); } return(partSim); }