Beispiel #1
0
        public static EngineSim New(PartSim theEngine,
                                    ModuleEngines engineMod,
                                    double atmosphere,
                                    float machNumber,
                                    bool vectoredThrust,
                                    bool fullThrust,
                                    LogMsg log)
        {
            float            maxFuelFlow                = engineMod.maxFuelFlow;
            float            minFuelFlow                = engineMod.minFuelFlow;
            float            thrustPercentage           = engineMod.thrustPercentage;
            List <Transform> thrustTransforms           = engineMod.thrustTransforms;
            List <float>     thrustTransformMultipliers = engineMod.thrustTransformMultipliers;
            Vector3          vecThrust = CalculateThrustVector(vectoredThrust ? thrustTransforms : null,
                                                               vectoredThrust ? thrustTransformMultipliers : null,
                                                               log);
            FloatCurve        atmosphereCurve = engineMod.atmosphereCurve;
            bool              atmChangeFlow   = engineMod.atmChangeFlow;
            FloatCurve        atmCurve        = engineMod.useAtmCurve ? engineMod.atmCurve : null;
            FloatCurve        velCurve        = engineMod.useVelCurve ? engineMod.velCurve : null;
            float             currentThrottle = engineMod.currentThrottle;
            float             IspG            = engineMod.g;
            bool              throttleLocked  = engineMod.throttleLocked || fullThrust;
            List <Propellant> propellants     = engineMod.propellants;
            bool              active          = engineMod.isOperational;
            float             resultingThrust = engineMod.resultingThrust;
            bool              isFlamedOut     = engineMod.flameout;

            EngineSim engineSim = pool.Borrow();

            engineSim.isp          = 0.0;
            engineSim.maxMach      = 0.0f;
            engineSim.actualThrust = 0.0;
            engineSim.partSim      = theEngine;
            engineSim.isActive     = active;
            engineSim.thrustVec    = vecThrust;
            engineSim.isFlamedOut  = isFlamedOut;
            engineSim.resourceConsumptions.Reset();
            engineSim.maxResourceConsumptions.Reset();
            engineSim.resourceFlowModes.Reset();
            engineSim.appliedForces.Clear();

            double flowRate    = 0.0;
            double maxFlowRate = 0.0;

            if (engineSim.partSim.hasVessel)
            {
                if (log != null)
                {
                    log.AppendLine("hasVessel is true");
                }

                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, engineSim.partSim.part.atmDensity, velCurve, machNumber, ref engineSim.maxMach);
                engineSim.isp          = atmosphereCurve.Evaluate((float)atmosphere);
                engineSim.fullThrust   = GetThrust(maxFuelFlow * flowModifier, engineSim.isp);
                engineSim.thrust       = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
                engineSim.actualThrust = engineSim.isActive ? resultingThrust : 0.0;
                if (log != null)
                {
                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
                }

                if (throttleLocked)
                {
                    if (log != null)
                    {
                        log.AppendLine("throttleLocked is true, using thrust for flowRate");
                    }
                    flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                }
                else
                {
                    if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false)
                    {
                        // TODO: This bit doesn't work for RF engines
                        if (log != null)
                        {
                            log.AppendLine("throttled up and not landed, using actualThrust for flowRate");
                        }
                        flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp);
                    }
                    else
                    {
                        if (log != null)
                        {
                            log.AppendLine("throttled down or landed, using thrust for flowRate");
                        }
                        flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                    }
                }

                maxFlowRate = GetFlowRate(engineSim.fullThrust, engineSim.isp);
            }
            else
            {
                if (log != null)
                {
                    log.buf.AppendLine("hasVessel is false");
                }
                float altitude     = BasicDeltaV.Instance.AtmosphereDepth;
                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, BasicDeltaV.Instance.CurrentCelestialBody.GetDensity(BasicDeltaV.Instance.CurrentCelestialBody.GetPressure(altitude), BasicDeltaV.Instance.CurrentCelestialBody.GetTemperature(altitude)), velCurve, machNumber, ref engineSim.maxMach);
                engineSim.isp          = atmosphereCurve.Evaluate((float)atmosphere);
                engineSim.fullThrust   = GetThrust(maxFuelFlow * flowModifier, engineSim.isp);
                engineSim.thrust       = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
                engineSim.actualThrust = 0d;
                if (log != null)
                {
                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
                    log.AppendLine("no vessel, using thrust for flowRate");
                }

                flowRate    = GetFlowRate(engineSim.thrust, engineSim.isp);
                maxFlowRate = GetFlowRate(engineSim.fullThrust, engineSim.isp);
            }

            if (log != null)
            {
                log.buf.AppendFormat("flowRate = {0:g6}\n", flowRate);
            }

            float flowMass = 0f;

            for (int i = 0; i < propellants.Count; ++i)
            {
                Propellant propellant = propellants[i];
                if (!propellant.ignoreForIsp)
                {
                    flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
                }
            }

            if (log != null)
            {
                log.buf.AppendFormat("flowMass = {0:g6}\n", flowMass);
            }

            for (int i = 0; i < propellants.Count; ++i)
            {
                Propellant propellant = propellants[i];

                if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
                {
                    continue;
                }

                double consumptionRate = propellant.ratio * flowRate / flowMass;

                if (log != null)
                {
                    log.buf.AppendFormat(
                        "Add consumption({0}, {1}:{2:d}) = {3:g6}\n",
                        ResourceContainer.GetResourceName(propellant.id),
                        theEngine.name,
                        theEngine.partId,
                        consumptionRate);
                }

                engineSim.resourceConsumptions.Add(propellant.id, consumptionRate);
                engineSim.resourceFlowModes.Add(propellant.id, (double)propellant.GetFlowMode());

                double maxConsumptionRate = propellant.ratio * maxFlowRate / flowMass;

                engineSim.maxResourceConsumptions.Add(propellant.id, maxConsumptionRate);
            }

            for (int i = 0; i < thrustTransforms.Count; i++)
            {
                Transform thrustTransform = thrustTransforms[i];
                Vector3d  direction       = thrustTransform.forward.normalized;
                Vector3d  position        = thrustTransform.position;

                AppliedForce appliedForce = AppliedForce.New(direction * engineSim.thrust * thrustTransformMultipliers[i], position);
                engineSim.appliedForces.Add(appliedForce);
            }

            return(engineSim);
        }
Beispiel #2
0
        public void GetSourceSet_Internal(int type, bool includeSurfaceMountedParts, List <PartSim> allParts, HashSet <PartSim> visited, HashSet <PartSim> allSources, bool checkMax, ref int priMax, LogMsg log, String indent)
        {
            if (log != null)
            {
                log.Append(indent, "GetSourceSet_Internal(", ResourceContainer.GetResourceName(type), ") for ")
                .AppendLine(name, ":", partId);
                indent += "  ";
            }

            // Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns as is.
            if (visited.Contains(this))
            {
                if (log != null)
                {
                    log.Append(indent, "Nothing added, already visited (", name, ":")
                    .AppendLine(partId + ")");
                }
                return;
            }

            if (log != null)
            {
                log.AppendLine(indent, "Adding this to visited");
            }

            visited.Add(this);

            // Rule 2: Part performs scan on start of every fuel pipe ending in it. This scan is done in order in which pipes were installed.
            // Then it makes an union of fuel tank sets each pipe scan returned. If the resulting list is not empty, it is returned as result.
            //MonoBehaviour.print("for each fuel line");

            int lastCount = allSources.Count;

            for (int i = 0; i < this.fuelTargets.Count; i++)
            {
                PartSim partSim = this.fuelTargets[i];
                if (partSim != null)
                {
                    if (visited.Contains(partSim))
                    {
                        if (log != null)
                        {
                            log.Append(indent, "Fuel target already visited, skipping (", partSim.name, ":")
                            .AppendLine(partSim.partId, ")");
                        }
                    }
                    else
                    {
                        if (log != null)
                        {
                            log.Append(indent, "Adding fuel target as source (", partSim.name, ":")
                            .AppendLine(partSim.partId, ")");
                        }

                        partSim.GetSourceSet_Internal(type, includeSurfaceMountedParts, allParts, visited, allSources, checkMax, ref priMax, log, indent);
                    }
                }
            }

            if (fuelCrossFeed)
            {
                if (includeSurfaceMountedParts)
                {
                    // check surface mounted fuel targets
                    for (int i = 0; i < surfaceMountFuelTargets.Count; i++)
                    {
                        PartSim partSim = this.surfaceMountFuelTargets[i];
                        if (partSim != null)
                        {
                            if (visited.Contains(partSim))
                            {
                                if (log != null)
                                {
                                    log.Append(indent, "Surface part already visited, skipping (", partSim.name, ":")
                                    .AppendLine(partSim.partId, ")");
                                }
                            }
                            else
                            {
                                if (log != null)
                                {
                                    log.Append(indent, "Adding surface part as source (", partSim.name, ":")
                                    .AppendLine(partSim.partId, ")");
                                }

                                partSim.GetSourceSet_Internal(type, includeSurfaceMountedParts, allParts, visited, allSources, checkMax, ref priMax, log, indent);
                            }
                        }
                    }
                }

                lastCount = allSources.Count;
                //MonoBehaviour.print("for each attach node");
                for (int i = 0; i < this.attachNodes.Count; i++)
                {
                    AttachNodeSim attachSim = this.attachNodes[i];
                    if (attachSim.attachedPartSim != null)
                    {
                        if (attachSim.nodeType == AttachNode.NodeType.Stack)
                        {
                            if ((string.IsNullOrEmpty(noCrossFeedNodeKey) == false && attachSim.id.Contains(noCrossFeedNodeKey)) == false)
                            {
                                if (visited.Contains(attachSim.attachedPartSim))
                                {
                                    if (log != null)
                                    {
                                        log.Append(indent, "Attached part already visited, skipping (", attachSim.attachedPartSim.name, ":")
                                        .AppendLine(attachSim.attachedPartSim.partId, ")");
                                    }
                                }
                                else
                                {
                                    bool flg = true;

                                    if (attachSim.attachedPartSim.isEnginePlate) //y u make me do dis.
                                    {
                                        foreach (AttachNodeSim att in attachSim.attachedPartSim.attachNodes)
                                        {
                                            if (att.attachedPartSim == this && att.id == "bottom")
                                            {
                                                flg = false;
                                            }
                                        }
                                    }

                                    if (flg)
                                    {
                                        if (log != null)
                                        {
                                            log.Append(indent, "Adding attached part as source  (", attachSim.attachedPartSim.name, ":")
                                            .AppendLine(attachSim.attachedPartSim.partId, ")");
                                        }

                                        attachSim.attachedPartSim.GetSourceSet_Internal(type, includeSurfaceMountedParts, allParts, visited, allSources, checkMax, ref priMax, log, indent);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // If the part is fuel container for searched type of fuel (i.e. it has capability to contain that type of fuel and the fuel
            // type was not disabled) and it contains fuel, it adds itself.
            if (checkMax ? (maxResources.HasType(type)) : (resources.HasType(type) && resourceFlowStates[type] > 0.0))
            {
                if (checkMax ? (maxResources[type] > SimManager.RESOURCE_MIN) : (resources[type] > resRequestRemainingThreshold))
                {
                    // Get the priority of this tank
                    int pri = GetResourcePriority();
                    if (pri > priMax)
                    {
                        // This tank is higher priority than the previously added ones so we clear the sources
                        // and set the priMax to this priority
                        allSources.Clear();
                        priMax = pri;
                    }
                    // If this is the correct priority then add this to the sources
                    if (pri == priMax)
                    {
                        if (log != null)
                        {
                            log.Append(indent, "Adding enabled tank as source (", name, ":")
                            .AppendLine(partId, ")");
                        }

                        allSources.Add(this);
                    }
                }
            }
            else
            {
                if (log != null)
                {
                    log.Append(indent, "Not fuel tank or disabled. HasType = ", resources.HasType(type))
                    .AppendLine("  FlowState = " + resourceFlowStates[type]);
                }
            }
        }
Beispiel #3
0
        public bool SetPossibleResourceDrains(LogMsg log, List <PartSim> allParts, HashSet <PartSim> drainingParts)
        {
            //DumpSourcePartSets(log, "before clear");
            foreach (HashSet <PartSim> sourcePartSet in fullSourcePartSets.Values)
            {
                sourcePartSet.Clear();
            }
            //DumpSourcePartSets(log, "after clear");

            for (int index = 0; index < this.resourceConsumptions.Types.Count; index++)
            {
                int type = this.resourceConsumptions.Types[index];

                if (!fullSourcePartSets.TryGetValue(type, out HashSet <PartSim> sourcePartSet))
                {
                    sourcePartSet = new HashSet <PartSim>();
                    fullSourcePartSets.Add(type, sourcePartSet);
                }

                switch ((ResourceFlowMode)this.resourceFlowModes[type])
                {
                case ResourceFlowMode.NO_FLOW:
                    if (partSim.maxResources[type] > SimManager.RESOURCE_MIN)
                    {
                        sourcePartSet.Add(partSim);
                    }
                    break;

                case ResourceFlowMode.ALL_VESSEL:
                case ResourceFlowMode.ALL_VESSEL_BALANCE:
                    for (int i = 0; i < allParts.Count; i++)
                    {
                        PartSim aPartSim = allParts[i];
                        if (aPartSim.maxResources[type] > SimManager.RESOURCE_MIN)
                        {
                            sourcePartSet.Add(aPartSim);
                        }
                    }
                    break;

                case ResourceFlowMode.STAGE_PRIORITY_FLOW:
                case ResourceFlowMode.STAGE_PRIORITY_FLOW_BALANCE:
                    //All vessel ordered by stage
                    if (log != null)
                    {
                        log.Append("Find ", ResourceContainer.GetResourceName(type), " sources for ", partSim.name)
                        .AppendLine(":", partSim.partId);
                    }
                    foreach (HashSet <PartSim> stagePartSet in stagePartSets.Values)
                    {
                        stagePartSet.Clear();
                    }
                    var maxStage = -1;

                    for (int i = 0; i < allParts.Count; i++)
                    {
                        var aPartSim = allParts[i];
                        //if (log != null) log.Append(aPartSim.name, ":" + aPartSim.partId, " contains ", aPartSim.resources[type])
                        //                  .AppendLine((aPartSim.resourceFlowStates[type] == 0) ? " (disabled)" : "");
                        if (aPartSim.maxResources[type] > SimManager.RESOURCE_MIN)
                        {
                            int stage = aPartSim.inverseStage;
                            if (stage > maxStage)
                            {
                                maxStage = stage;
                            }

                            if (!stagePartSets.TryGetValue(stage, out HashSet <PartSim> tempPartSet))
                            {
                                tempPartSet = new HashSet <PartSim>();
                                stagePartSets.Add(stage, tempPartSet);
                            }
                            tempPartSet.Add(aPartSim);
                        }
                    }

                    //Add resource containers in order by stage
                    for (int j = maxStage; j >= -1; j--)
                    {
                        //if (log != null) log.AppendLine("Testing stage ", j);

                        if (stagePartSets.TryGetValue(j, out HashSet <PartSim> stagePartSet) && stagePartSet.Count > 0)
                        {
                            //if (log != null) log.AppendLine("Not empty");
                            // We have to copy the contents of the set here rather than copying the set reference or
                            // bad things (tm) happen
                            foreach (PartSim aPartSim in stagePartSet)
                            {
                                sourcePartSet.Add(aPartSim);
                            }
                            break;
                        }
                    }
                    break;

                case ResourceFlowMode.STACK_PRIORITY_SEARCH:
                case ResourceFlowMode.STAGE_STACK_FLOW:
                case ResourceFlowMode.STAGE_STACK_FLOW_BALANCE:
                    visited.Clear();
                    //Resource containers limited to current stage
                    if (log != null)
                    {
                        log.Append("Find ", ResourceContainer.GetResourceName(type), " sources for ", partSim.name)
                        .AppendLine(":", partSim.partId);
                    }

                    partSim.GetSourceSet(type, true, allParts, visited, sourcePartSet, true, log, "");
                    break;

                default:
                    if (log != null)
                    {
                        log.Append("SetResourceDrains(", partSim.name, ":", partSim.partId)
                        .AppendLine(") Unexpected flow type for ", ResourceContainer.GetResourceName(type), ")");
                    }
                    break;
                }
            }

            // If we don't have sources for all the needed resources then return false without setting up any drains
            for (int i = 0; i < this.resourceConsumptions.Types.Count; i++)
            {
                int type = this.resourceConsumptions.Types[i];

                if (!fullSourcePartSets.TryGetValue(type, out HashSet <PartSim> sourcePartSet) || sourcePartSet.Count == 0)
                {
                    if (log != null)
                    {
                        log.AppendLine("No source of ", ResourceContainer.GetResourceName(type));
                    }

                    return(false);
                }
            }

            // Now we set the drains on the members of the sets and update the draining parts set
            for (int i = 0; i < this.resourceConsumptions.Types.Count; i++)
            {
                HashSet <PartSim> sourcePartSet = fullSourcePartSets[resourceConsumptions.Types[i]];

                // Loop through the members of the set
                foreach (PartSim partSim in sourcePartSet)
                {
                    drainingParts.Add(partSim);
                }
            }

            return(true);
        }
Beispiel #4
0
        public void DumpPartToLog(LogMsg log, String prefix, List <PartSim> allParts = null)
        {
            if (log == null)
            {
                return;
            }

            log.Append(prefix);
            log.Append(name);
            log.Append(":[id = ", partId, ", decouple = ", decoupledInStage);
            log.Append(", invstage = ", inverseStage);

            //log.Append(", vesselName = '", vesselName, "'");
            //log.Append(", vesselType = ", SimManager.GetVesselTypeString(vesselType));
            //log.Append(", initialVesselName = '", initialVesselName, "'");

            log.Append(", isNoPhys = ", isNoPhysics);
            log.buf.AppendFormat(", baseMass = {0}", baseMass);
            log.buf.AppendFormat(", baseMassForCoM = {0}", baseMassForCoM);

            log.Append(", fuelCF = {0}", fuelCrossFeed);
            log.Append(", noCFNKey = '{0}'", noCrossFeedNodeKey);

            log.Append(", isSep = {0}", isSepratron);

            try
            {
                for (int i = 0; i < resources.Types.Count; i++)
                {
                    int type = resources.Types[i];
                    log.buf.AppendFormat(", {0} = {1:g6}", ResourceContainer.GetResourceName(type), resources[type]);
                }
            }
            catch (Exception e)
            {
                log.Append("error dumping part resources " + e.ToString());
            }

            try
            {
                if (attachNodes.Count > 0)
                {
                    log.Append(", attached = <");
                    attachNodes[0].DumpToLog(log);
                    for (int i = 1; i < attachNodes.Count; i++)
                    {
                        log.Append(", ");
                        if (attachNodes[i] != null)
                        {
                            attachNodes[i].DumpToLog(log);                         //its u, isn't it?
                        }
                    }
                    log.Append(">");
                }
            }
            catch (Exception e)
            {
                log.Append("error dumping part nodes" + e.ToString());
            }

            try
            {
                if (surfaceMountFuelTargets.Count > 0)
                {
                    log.Append(", surface = <");
                    if (surfaceMountFuelTargets[0] != null)
                    {
                        log.Append(surfaceMountFuelTargets[0].name, ":", surfaceMountFuelTargets[0].partId);
                    }
                    for (int i = 1; i < surfaceMountFuelTargets.Count; i++)
                    {
                        if (surfaceMountFuelTargets[i] != null)
                        {
                            log.Append(", ", surfaceMountFuelTargets[i].name, ":", surfaceMountFuelTargets[i].partId);                                     //no it was u.
                        }
                    }
                    log.Append(">");
                }
            }
            catch (Exception e)
            {
                log.Append("error dumping part surface fuels " + e.ToString());
            }

            // Add more info here

            log.AppendLine("]");

            if (allParts != null)
            {
                String newPrefix = prefix + " ";
                for (int i = 0; i < allParts.Count; i++)
                {
                    PartSim partSim = allParts[i];
                    if (partSim.parent == this)
                    {
                        partSim.DumpPartToLog(log, newPrefix, allParts);
                    }
                }
            }
        }