Beispiel #1
0
        public PartSim(Part thePart, int id, double atmosphere, LogMsg log)
        {
            part = thePart;
            partId = id;
            name = part.partInfo.name;

            if (log != null)
                log.buf.AppendLine("Create PartSim for " + name);

            parent = null;
            parentAttach = part.attachMode;
            fuelCrossFeed = part.fuelCrossFeed;
            noCrossFeedNodeKey = part.NoCrossFeedNodeKey;
            decoupledInStage = DecoupledInStage(part);
            isFuelLine = part is FuelLine;
            isFuelTank = part is FuelTank;
            isSepratron = IsSepratron();
            inverseStage = part.inverseStage;
            //MonoBehaviour.print("inverseStage = " + inverseStage);

            cost = part.partInfo.cost;
            foreach (PartResource resource in part.Resources)
            {
                cost -= (float)((resource.maxAmount - resource.amount) * resource.info.unitCost);
            }

            // Work out if the part should have no physical significance
            isNoPhysics = part.HasModule<LaunchClamp>() ||
                            part.physicalSignificance == Part.PhysicalSignificance.NONE ||
                            part.PhysicsSignificance == 1;

            if (!isNoPhysics)
                baseMass = part.mass;

            if (SimManager.logOutput)
                MonoBehaviour.print((isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + part.mass);

            foreach (PartResource resource in part.Resources)
            {
                // 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 (SimManager.logOutput)
                        MonoBehaviour.print(resource.resourceName + " = " + resource.amount);

                    resources.Add(resource.info.id, resource.amount);
                    resourceFlowStates.Add(resource.info.id, resource.flowState ? 1 : 0);
                }
                else
                {
                    MonoBehaviour.print(resource.resourceName + " is NaN. Skipping.");
                }
            }

            startMass = GetMass();

            hasVessel = (part.vessel != null);
            isLanded = hasVessel && part.vessel.Landed;
            if (hasVessel)
            {
                vesselName = part.vessel.vesselName;
                vesselType = part.vesselType;
            }
            initialVesselName = part.initialVesselName;

            hasMultiModeEngine = part.HasModule<MultiModeEngine>();
            hasModuleEnginesFX = part.HasModule<ModuleEnginesFX>();
            hasModuleEngines = part.HasModule<ModuleEngines>();

            isEngine = hasMultiModeEngine || hasModuleEnginesFX || hasModuleEngines;

            if (SimManager.logOutput)
                MonoBehaviour.print("Created " + name + ". Decoupled in stage " + decoupledInStage);
        }
Beispiel #2
0
        public EngineSim(PartSim theEngine,
                            double atmosphere,
                            double velocity,
                            float maxThrust,
                            float minThrust,
                            float thrustPercentage,
                            float requestedThrust,
                            Vector3 vecThrust,
                            float realIsp,
                            FloatCurve atmosphereCurve,
                            FloatCurve velocityCurve,
                            bool throttleLocked,
                            List<Propellant> propellants,
                            bool active,
                            bool correctThrust)
        {
            StringBuilder buffer = null;
            //MonoBehaviour.print("Create EngineSim for " + theEngine.name);
            //MonoBehaviour.print("maxThrust = " + maxThrust);
            //MonoBehaviour.print("minThrust = " + minThrust);
            //MonoBehaviour.print("thrustPercentage = " + thrustPercentage);
            //MonoBehaviour.print("requestedThrust = " + requestedThrust);
            //MonoBehaviour.print("velocity = " + velocity);

            partSim = theEngine;

            isActive = active;
            thrust = (maxThrust - minThrust) * (thrustPercentage / 100f) + minThrust;
            //MonoBehaviour.print("thrust = " + thrust);

            thrustVec = vecThrust;

            double flowRate = 0d;
            if (partSim.hasVessel)
            {
                //MonoBehaviour.print("hasVessel is true");
                actualThrust = requestedThrust;
                if (velocityCurve != null)
                {
                    actualThrust *= velocityCurve.Evaluate((float)velocity);
                    //MonoBehaviour.print("actualThrust at velocity = " + actualThrust);
                }

                isp = atmosphereCurve.Evaluate((float)partSim.part.staticPressureAtm);
                if (isp == 0d)
                    MonoBehaviour.print("Isp at " + partSim.part.staticPressureAtm + " is zero. Flow rate will be NaN");

                if (correctThrust && realIsp == 0)
                {
                    float ispsl = atmosphereCurve.Evaluate(0);
                    if (ispsl != 0)
                    {
                        thrust = thrust * isp / ispsl;
                    }
                    else
                    {
                        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
                    }
                    //MonoBehaviour.print("corrected thrust = " + thrust);
                }

                if (velocityCurve != null)
                {
                    thrust *= velocityCurve.Evaluate((float)velocity);
                    //MonoBehaviour.print("thrust at velocity = " + thrust);
                }

                if (throttleLocked)
                {
                    //MonoBehaviour.print("throttleLocked is true");
                    flowRate = thrust / (isp * 9.81d);
                }
                else
                {
                    if (partSim.isLanded)
                    {
                        //MonoBehaviour.print("partSim.isLanded is true, mainThrottle = " + FlightInputHandler.state.mainThrottle);
                        flowRate = Math.Max(0.000001d, thrust * FlightInputHandler.state.mainThrottle) / (isp * 9.81d);
                    }
                    else
                    {
                        if (requestedThrust > 0)
                        {
                            if (velocityCurve != null)
                            {
                                requestedThrust *= velocityCurve.Evaluate((float)velocity);
                                //MonoBehaviour.print("requestedThrust at velocity = " + requestedThrust);
                            }

                            //MonoBehaviour.print("requestedThrust > 0");
                            flowRate = requestedThrust / (isp * 9.81d);
                        }
                        else
                        {
                            //MonoBehaviour.print("requestedThrust <= 0");
                            flowRate = thrust / (isp * 9.81d);
                        }
                    }
                }
            }
            else
            {
                //MonoBehaviour.print("hasVessel is false");
                isp = atmosphereCurve.Evaluate((float)atmosphere);
                if (isp == 0d)
                    MonoBehaviour.print("Isp at " + atmosphere + " is zero. Flow rate will be NaN");
                if (correctThrust)
                {
                    float ispsl = atmosphereCurve.Evaluate(0);
                    if (ispsl != 0)
                    {
                        thrust = thrust * isp / ispsl;
                    }
                    else
                    {
                        MonoBehaviour.print("Isp at sea level is zero. Unable to correct thrust.");
                    }
                    //MonoBehaviour.print("corrected thrust = " + thrust);
                }

                if (velocityCurve != null)
                {
                    thrust *= velocityCurve.Evaluate((float)velocity);
                    //MonoBehaviour.print("thrust at velocity = " + thrust);
                }

                flowRate = thrust / (isp * 9.81d);
            }

            if (SimManager.logOutput)
            {
                buffer = new StringBuilder(1024);
                buffer.AppendFormat("flowRate = {0:g6}\n", flowRate);
            }

            float flowMass = 0f;
            foreach (Propellant propellant in propellants)
                flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);

            if (SimManager.logOutput)
                buffer.AppendFormat("flowMass = {0:g6}\n", flowMass);

            foreach (Propellant propellant in propellants)
            {
                if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
                    continue;

                double consumptionRate = propellant.ratio * flowRate / flowMass;
                if (SimManager.logOutput)
                    buffer.AppendFormat("Add consumption({0}, {1}:{2:d}) = {3:g6}\n", ResourceContainer.GetResourceName(propellant.id), theEngine.name, theEngine.partId, consumptionRate);
                resourceConsumptions.Add(propellant.id, consumptionRate);
            }

            if (SimManager.logOutput)
                MonoBehaviour.print(buffer);
        }
Beispiel #3
0
 public void SetupParent(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
 {
     if (part.parent != null)
     {
         parent = null;
         if (partSimLookup.TryGetValue(part.parent, out parent))
         {
             if (log != null)
                 log.buf.AppendLine("Parent part is " + parent.name + ":" + parent.partId);
         }
         else
         {
             if (log != null)
                 log.buf.AppendLine("No PartSim for parent part (" + part.parent.partInfo.name + ")");
         }
     }
 }
Beispiel #4
0
        private bool DrainFromSourceBeforeSelf(int type, PartSim source)
        {
            if (resources[type] < 1f)
            {
                return true;
            }

            if (source.part != this.part.parent)
            {
                return true;
            }

            if (this.part.parent == null)
            {
                return true;
            }

            foreach (AttachNode attachNode in this.part.parent.attachNodes)
            {
                if (attachNode.attachedPart == this.part && attachNode.nodeType != AttachNode.NodeType.Stack)
                {
                    return false;
                }
            }

            return true;
        }
Beispiel #5
0
 public void RemoveSourcePart(PartSim part)
 {
     if (sourceParts.Contains(part))
     {
         sourceParts.Remove(part);
     }
 }
Beispiel #6
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(List<Part> parts, double theGravity, double theAtmosphere = 0, double theVelocity = 0, bool dumpTree = false, bool vectoredThrust = false)
        {
            LogMsg log = null;
            if (SimManager.logOutput)
            {
                log = new LogMsg();
                log.buf.AppendLine("PrepareSimulation started");
                dumpTree = true;
            }
            _timer.Start();

            // Store the parameters in members for ease of access in other functions
            partList = parts;
            gravity = theGravity;
            atmosphere = theAtmosphere;
            velocity = theVelocity;
            lastStage = Staging.lastStage;
            //MonoBehaviour.print("lastStage = " + lastStage);

            // Create the lists for our simulation parts
            allParts = new List<PartSim>();
            allFuelLines = new List<PartSim>();
            drainingParts = new HashSet<PartSim>();
            allEngines = new List<EngineSim>();
            activeEngines = new List<EngineSim>();
            drainingResources = new HashSet<int>();

            // A dictionary for fast lookup of Part->PartSim during the preparation phase
            Dictionary<Part, PartSim> partSimLookup = new Dictionary<Part, PartSim>();

            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;
            foreach (Part part in partList)
            {
                // 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.buf.AppendLine("Part " + part.name + " appears in vessel list more than once");
                    continue;
                }

                // Create the PartSim
                PartSim partSim = new PartSim(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, velocity, vectoredThrust, log);

                partId++;
            }

            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
            foreach (PartSim partSim in allParts)
            {
                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)
            {
                foreach (PartSim partSim in allFuelLines)
                {
                    if ((partSim.part as FuelLine).target != null)
                    {
                        PartSim targetSim;
                        if (partSimLookup.TryGetValue((partSim.part as FuelLine).target, out targetSim))
                        {
                            if (log != null)
                                log.buf.AppendLine("Fuel line target is " + targetSim.name + ":" + targetSim.partId);

                            targetSim.fuelTargets.Add(partSim.parent);
                        }
                        else
                        {
                            if (log != null)
                                log.buf.AppendLine("No PartSim for fuel line target (" + partSim.part.partInfo.name + ")");
                        }
                    }
                    else
                    {
                        if (log != null)
                            log.buf.AppendLine("Fuel line target is null");
                    }
                }
            }

            //MonoBehaviour.print("SetupAttachNodes and count stages");
            foreach (PartSim partSim in allParts)
            {
                partSim.SetupAttachNodes(partSimLookup, log);
                if (partSim.decoupledInStage >= lastStage)
                    lastStage = partSim.decoupledInStage + 1;
            }

            // And finally release the Part references from all the PartSims
            //MonoBehaviour.print("ReleaseParts");
            foreach (PartSim partSim in allParts)
                partSim.ReleasePart();

            // And dereference the core's part list
            partList = null;

            _timer.Stop();
            if (log != null)
            {
                log.buf.AppendLine("PrepareSimulation: " + _timer.ElapsedMilliseconds + "ms");
                log.Flush();
            }

            if (dumpTree)
                Dump();

            return true;
        }
Beispiel #7
0
        private void BuildVessel(List<Part> parts, double atmosphere)
        {
            partSims = new List<PartSim>();
            Hashtable partSimLookup = new Hashtable();
            foreach (Part part in parts)
            {
                PartSim partSim = new PartSim(part, atmosphere);

                if (partSim.decoupledInStage < currentStage)
                {
                    partSim.SetResourceConsumptions();
                    partSims.Add(partSim);
                    partSimLookup.Add(part, partSim);
                }
            }

            foreach (PartSim partSim in partSims)
            {
                partSim.SetSourceNodes(partSimLookup);
            }
        }
Beispiel #8
0
 public AttachNodeSim(PartSim partSim, String newId, AttachNode.NodeType newNodeType)
 {
     attachedPartSim = partSim;
     nodeType = newNodeType;
     id = newId;
 }