예제 #1
0
        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"));
                }
            }
        }
예제 #2
0
 private void SetSasInfo()
 {
     if (PartExtensions.HasModule <ModuleSAS>(selectedPart))
     {
         infoItems.Add(PartInfoItem.Create("SAS Equiped"));
     }
 }
예제 #3
0
        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()));
                    }
                }
            }
        }
예제 #4
0
 private void SetScienceContainerInfo()
 {
     if (PartExtensions.HasModule <ModuleScienceContainer>(selectedPart))
     {
         infoItems.Add(PartInfoItem.Create("Science Container"));
     }
 }
예제 #5
0
 private void SetSingleActivationInfo()
 {
     if (PartExtensions.HasModule <ModuleAnimateGeneric>(selectedPart, m => m.isOneShot))
     {
         infoItems.Add(PartInfoItem.Create("Single Activation"));
     }
 }
예제 #6
0
 private void SetMassItems()
 {
     if (selectedPart.physicalSignificance == Part.PhysicalSignificance.FULL)
     {
         infoItems.Add(PartInfoItem.Create("Mass", Units.ToMass(PartExtensions.GetDryMass(selectedPart), PartExtensions.GetWetMass(selectedPart))));
     }
 }
예제 #7
0
        private void SetGimbalInfo()
        {
            var moduleGimbal = PartExtensions.GetModule <ModuleGimbal>(selectedPart);

            if (moduleGimbal != null)
            {
                infoItems.Add(PartInfoItem.Create("Thrust Vectoring", moduleGimbal.gimbalRange.ToString("F2")));
            }
        }
예제 #8
0
        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"));
            }
        }
예제 #9
0
        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")));
            }
        }
예제 #10
0
        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"));
                }
            }
        }
예제 #11
0
        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"));
            }
        }
예제 #12
0
        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()));
                }
            }
        }
예제 #13
0
        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"));
                }
            }
        }
예제 #14
0
        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);
        }
예제 #15
0
        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()));
                }
            }
        }
예제 #16
0
        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");
            }
        }
예제 #18
0
        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);
        }
예제 #19
0
        // 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);
        }
예제 #20
0
 private void SetCostInfo()
 {
     infoItems.Add(PartInfoItem.Create("Cost", Units.ConcatF(PartExtensions.GetCostDry(selectedPart), PartExtensions.GetCostWet(selectedPart))));
 }
예제 #21
0
        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);
        }