Пример #1
0
        // Static methods

        // Generate list of PersistentPropellant from propellant list
        public static List <PersistentPropellant> MakeList(List <Propellant> plist)
        {
            // Sum of ratios of propellants with mass
            var ratioMassSum = 0.0;
            // Create list of PersistentPropellant and calculate ratioSum & ratioMassSum
            var pplist = new List <PersistentPropellant>();

            foreach (var p in plist)
            {
                var pp = new PersistentPropellant(p);
                pplist.Add(pp);
                if (pp.density > 0.0)
                {
                    ratioMassSum += pp.ratio;
                }
            }

            // Normalize ratios to ratioMassSum
            if (ratioMassSum > 0)
            {
                foreach (var pp in pplist)
                {
                    pp.normalizedRatio = pp.ratio / ratioMassSum;
                }
            }

            return(pplist);
        }
Пример #2
0
        private double RequestResource(PersistentPropellant propellant, double demand, bool simulate = false)
        {
            if (propellant.density > 0 && !vessel.packed)
            {
                return(demand);
            }

            if (!useKerbalismInFlight)
            {
                return(part.RequestResource(propellant.definition.id, demand, propellant.propellant.GetFlowMode(), simulate));
            }

            _availablePartResources.TryGetValue(propellant.definition.name, out var currentAmount);

            var available = Math.Min(currentAmount, demand);

            if (simulate)
            {
                _availablePartResources[propellant.definition.name] = Math.Max(0, currentAmount - demand);
            }
            else
            {
                var demandPerSecond = demand / TimeWarp.fixedDeltaTime;

                _kerbalismResourceChangeRequest.TryGetValue(propellant.definition.name, out var currentDemand);
                _kerbalismResourceChangeRequest[propellant.definition.name] = currentDemand - demandPerSecond;
            }

            return(available);
        }
Пример #3
0
        public double UpdateBuffer(PersistentPropellant propellant, double baseSize)
        {
            var requiredBufferSize = useDynamicBuffer ? Math.Max(baseSize / TimeWarp.fixedDeltaTime * 10 * buffersizeMult, baseSize * buffersizeMult) : Math.Max(0, propellant.maxamount - baseSize);

            if (previousfixedDeltaTime == TimeWarp.fixedDeltaTime)
            {
                return(requiredBufferSize);
            }

            var amountRatio = propellant.maxamount > 0 ? Math.Min(1, propellant.amount / propellant.maxamount) : 0;

            dynamicBufferSize = useDynamicBuffer ? requiredBufferSize : 0;

            var partresource = part.Resources[propellant.definition.name];

            if (partresource == null)
            {
                var node = new ConfigNode("RESOURCE");
                node.AddValue("name", propellant.definition.name);
                node.AddValue("maxAmount", 0);
                node.AddValue("amount", 0);
                this.part.AddResource(node);

                partresource = part.Resources[propellant.definition.name];
            }

            partresource.maxAmount = dynamicBufferSize;
            partresource.amount    = dynamicBufferSize * amountRatio;

            previousfixedDeltaTime = TimeWarp.fixedDeltaTime;

            return(requiredBufferSize);
        }
Пример #4
0
        private PersistentPropellant LoadPropellantAvailability(PersistentPropellant currentPersistentPropellant)
        {
            var activePropellant = currentPersistentPropellant;

            var activePropellants = _persistentEngines.SelectMany(pe => pe.moduleEngines.SelectMany(pl =>
                                                                                                    pl.propellants.Where(pp =>
                                                                                                                         pp.missionTime == vessel.missionTime &&
                                                                                                                         pp.definition.id == currentPersistentPropellant.definition.id))).ToList();

            if (activePropellants.Any())
            {
                return(activePropellants.First());
            }

            // store mission time to prevent other engines doing unnecessary work
            currentPersistentPropellant.missionTime = vessel.missionTime;
            // determine amount and maxAmount at start of PersistentEngine testing
            part.GetConnectedResourceTotals(currentPersistentPropellant.definition.id,
                                            currentPersistentPropellant.propellant.GetFlowMode(), out currentPersistentPropellant.amount,
                                            out currentPersistentPropellant.maxAmount, true);
            // calculate total demand on operational engines
            currentPersistentPropellant.totalEnginesDemand = _persistentEngines
                                                             .Where(e => e.currentEngine.engine.getIgnitionState)
                                                             .Sum(m => m.currentEngine.propellants
                                                                  .Where(l => l.definition.id == currentPersistentPropellant.definition.id)
                                                                  .Sum(l => l.normalizedDemand));

            return(activePropellant);
        }
Пример #5
0
        // Initialization
        public override void OnLoad(ConfigNode node)
        {
            // Run base OnLoad method
            base.OnLoad(node);

            Debug.Log("[PersistentThrust]: OnLoad called for " + part.partInfo.title + " " + part.persistentId);

            // Populate moduleEngine and moduleEngineFx fields
            FindModuleEngines();

            // Initialize PersistentPropellant list
            if (isMultiMode)
            {
                moduleEngines[0].propellants = PersistentPropellant.MakeList(moduleEngines[0].engine.propellants);
                moduleEngines[1].propellants = PersistentPropellant.MakeList(moduleEngines[1].engine.propellants);

                moduleEngines[0].averageDensity = moduleEngines[0].propellants.AverageDensity();
                moduleEngines[1].averageDensity = moduleEngines[1].propellants.AverageDensity();
            }
            else
            {
                foreach (var engine in moduleEngines)
                {
                    engine.propellants    = PersistentPropellant.MakeList(engine.engine.propellants);
                    engine.averageDensity = engine.propellants.AverageDensity();
                }
            }
        }
Пример #6
0
        // Initialization
        public override void OnLoad(ConfigNode node)
        {
            // Run base OnLoad method
            base.OnLoad(node);

            // Populate engine and engineFX fields
            FindModuleEngines();

            if (IsPersistentEngine)
            {
                // Initialize PersistentPropellant list
                pplist = PersistentPropellant.MakeList(engine.propellants);

                // Initialize density of propellant used in deltaV and mass calculations
                densityAverage = pplist.AverageDensity();
            }
        }
        // Static methods
        // Generate list of PersistentPropellant from propellant list
        public static List<PersistentPropellant> MakeList(List<Propellant> plist)
        {
            // Sum of ratios of propellants with mass
            var ratioMassSum = 0.0;
            // Create list of PersistentPropellant and calculate ratioSum & ratioMassSum
            var pplist = new List<PersistentPropellant>();
            foreach (var p in plist) {
            var pp = new PersistentPropellant(p);
            pplist.Add(pp);
            if (pp.density > 0.0) {
            ratioMassSum += pp.ratio;
            }
            }
            // Normalize ratios to ratioMassSum
            foreach (var pp in pplist) {
            pp.normalizedRatio = pp.ratio / ratioMassSum;
            }

            return pplist;
        }
Пример #8
0
        private PersistentPropellant LoadPropellantAvailability(PersistentPropellant pp)
        {
            var activePropellant     = pp;
            var firstProcessedEngine = persistentEngines.FirstOrDefault(m => m.pplist.Any(l => l.missionTime == vessel.missionTime && l.definition.id == pp.definition.id));

            if (firstProcessedEngine == null)
            {
                // store mission time to prevent other engines doing unnesisary work
                pp.missionTime = vessel.missionTime;
                // determine amount and maxamount at start of PersistenEngine testing
                part.GetConnectedResourceTotals(pp.definition.id, pp.propellant.GetFlowMode(), out pp.amount, out pp.maxamount, true);
                // calculate total demand
                pp.totalEnginesDemand = persistentEngines.Sum(m => m.pplist.Where(l => l.definition.id == pp.definition.id).Sum(l => l.normalizedDemand));
            }
            else
            {
                activePropellant = firstProcessedEngine.pplist.First(m => m.definition.id == pp.definition.id);
            }

            return(activePropellant);
        }
Пример #9
0
        // Apply demanded resources & return results
        // Updated depleted boolean flag if resource request failed
        public virtual double[] ApplyDemands(double[] demands, ref float finalPropellantReqMetFactor)
        {
            double overallPropellantReqMet = 1;

            var demandsOut = new double[currentEngine.propellants.Count];

            // first do a simulation run to determine the propellant availability so we don't over consume
            for (var i = 0; i < currentEngine.propellants.Count; i++)
            {
                currentEngine.autoMaximizePersistentIsp = false;

                PersistentPropellant persistentPropellant = currentEngine.propellants[i];
                // Request resources if:
                // - resource has mass & request mass flag true
                // - resource massless & request massless flag true
                if ((!(persistentPropellant.density > 0) || !requestPropMass) && (persistentPropellant.density != 0 || !requestPropMassless))
                {
                    continue;
                }

                persistentPropellant.demandIn = demands[i];
                var storageModifier = 1.0;

                // Process massless propellants like ElectricCharge separately
                if (persistentPropellant.density == 0)
                {
                    // find initial resource amount for propellant
                    var availablePropellant = LoadPropellantAvailability(persistentPropellant);

                    _availablePartResources.TryGetValue(persistentPropellant.definition.name, out var kerbalismAmount);

                    var currentPropellantAmount = useKerbalismInFlight ? kerbalismAmount : availablePropellant.amount;

                    // update power buffer
                    bufferSize = UpdateBuffer(availablePropellant, persistentPropellant.demandIn);

                    var bufferedTotalEnginesDemand = Math.Min(availablePropellant.maxAmount, availablePropellant.totalEnginesDemand * bufferSizeMult);

                    if (bufferedTotalEnginesDemand > currentPropellantAmount && availablePropellant.totalEnginesDemand > 0)
                    {
                        storageModifier = Math.Min(1, (persistentPropellant.demandIn / availablePropellant.totalEnginesDemand) + currentPropellantAmount / bufferedTotalEnginesDemand * (persistentPropellant.demandIn / availablePropellant.totalEnginesDemand));
                    }

                    if (!MaximizePersistentPower && currentPropellantAmount < bufferSize)
                    {
                        storageModifier *= currentPropellantAmount / bufferSize;
                    }
                }

                persistentPropellant.demandOut = IsInfinite(persistentPropellant.propellant)
                    ? persistentPropellant.demandIn
                    : RequestResource(persistentPropellant, persistentPropellant.demandIn * storageModifier, true);

                var propellantFoundRatio = persistentPropellant.demandOut >= persistentPropellant.demandIn
                    ? 1 : persistentPropellant.demandIn > 0 ? persistentPropellant.demandOut / persistentPropellant.demandIn : 1;

                if (propellantFoundRatio < overallPropellantReqMet)
                {
                    overallPropellantReqMet = propellantFoundRatio;
                }

                if (persistentPropellant.propellant.resourceDef.density > 0)
                {
                    // reset stabilize Queue when out of mass propellant
                    if (propellantFoundRatio < 1)
                    {
                        currentEngine.propellantReqMetFactorQueue.Clear();
                    }
                }
                else if (propellantFoundRatio == 0)
                {
                    // reset stabilize Queue when out power for too long
                    if (currentEngine.missingPowerCountdown <= 0)
                    {
                        currentEngine.propellantReqMetFactorQueue.Clear();
                    }
                    currentEngine.missingPowerCountdown--;
                }
                else
                {
                    currentEngine.missingPowerCountdown = missingPowerCountdownSize;
                }
            }

            // attempt to stabilize thrust output with First In Last Out Queue
            currentEngine.propellantReqMetFactorQueue.Enqueue((float)overallPropellantReqMet);
            if (currentEngine.propellantReqMetFactorQueue.Count() > propellantReqMetFactorQueueSize)
            {
                currentEngine.propellantReqMetFactorQueue.Dequeue();
            }
            var averagePropellantReqMetFactor = currentEngine.propellantReqMetFactorQueue.Average();

            if (averagePropellantReqMetFactor < minimumPropellantReqMetFactor)
            {
                currentEngine.autoMaximizePersistentIsp = true;
            }

            finalPropellantReqMetFactor = !vessel.packed || MaximizePersistentIsp || currentEngine.autoMaximizePersistentIsp ? averagePropellantReqMetFactor : Mathf.Pow(averagePropellantReqMetFactor, fudgeExponent);

            // secondly we can consume the resource based on propellant availability
            for (var i = 0; i < currentEngine.propellants.Count; i++)
            {
                var pp = currentEngine.propellants[i];
                // Request resources if:
                // - resource has mass & request mass flag true
                // - resource massless & request massless flag true
                if ((pp.density > 0 && requestPropMass) || (pp.density == 0 && requestPropMassless))
                {
                    var demandIn = pp.density > 0
                        ? MaximizePersistentIsp || currentEngine.autoMaximizePersistentIsp ? averagePropellantReqMetFactor * demands[i] :  demands[i]
                        : overallPropellantReqMet * demands[i];

                    var demandOut = IsInfinite(pp.propellant) ? demandIn : RequestResource(pp, demandIn, false);
                    demandsOut[i] = demandOut;
                }
                // Otherwise demand is 0
                else
                {
                    demandsOut[i] = 0;
                }
            }
            // Return demand outputs
            return(demandsOut);
        }