예제 #1
0
        private static ModuleGeneratorData LoadModuleGenerator(int partIndex, ProtoPartSnapshot protoPartSnapshot, VesselData vesselData, Part protoPart)
        {
            var moduleGenerators = protoPart?.FindModulesImplementing <ModuleGenerator>();

            if (moduleGenerators is null || moduleGenerators.Any() == false)
            {
                return(null);
            }

            List <int> protoPartModuleSnapshotIndexes = new List <int>();
            List <ProtoPartModuleSnapshot> protoPartModuleSnapshots = new List <ProtoPartModuleSnapshot>();

            for (int i = 0; i < protoPartSnapshot.modules.Count; i++)
            {
                ProtoPartModuleSnapshot protoPartModuleSnapshot = protoPartSnapshot.modules[i];

                if (protoPartModuleSnapshot.moduleName == nameof(ModuleGenerator))
                {
                    protoPartModuleSnapshotIndexes.Add(i);
                    protoPartModuleSnapshots.Add(protoPartModuleSnapshot);
                }
            }

            var moduleGeneratorData = new ModuleGeneratorData
            {
                PartIndex         = partIndex,
                ProtoPart         = protoPart,
                ProtoPartSnapshot = protoPartSnapshot,
                PersistentPartId  = protoPartSnapshot.persistentId,
                ProtoPartModuleSnapshotIndexes = protoPartModuleSnapshotIndexes,
                ModuleGenerators = moduleGenerators
            };

            // calculate tweakScale multiplier
            if (vesselData.PartSizeMultipliers.TryGetValue(protoPartSnapshot.persistentId, out double partSizeMultiplier))
            {
                var tweakScaleExponents = TweaksSaleHelper.GetTweakScaleExponents(nameof(ModuleGenerator));

                if (tweakScaleExponents.Exponents.TryGetValue("outputResources.rate", out double outputExponent))
                {
                    moduleGeneratorData.OutputMultiplier = Math.Pow(partSizeMultiplier, outputExponent);
                }

                if (tweakScaleExponents.Exponents.TryGetValue("inputResources.rate", out double inputExponent))
                {
                    moduleGeneratorData.InputMultiplier = Math.Pow(partSizeMultiplier, inputExponent);
                }
            }

            // readout persistent data
            for (int i = 0; i < moduleGenerators.Count; i++)
            {
                ModuleGenerator         moduleGenerator         = moduleGenerators[i];
                ProtoPartModuleSnapshot protoPartModuleSnapshot = protoPartModuleSnapshots[i];

                moduleGenerator.generatorIsActive = bool.Parse(protoPartModuleSnapshot.moduleValues.GetValue(nameof(moduleGenerator.generatorIsActive)));
                moduleGenerator.throttle          = float.Parse(protoPartModuleSnapshot.moduleValues.GetValue(nameof(moduleGenerator.throttle)));
            }

            vesselData.Generators.Add(protoPartSnapshot.persistentId, moduleGeneratorData);

            return(moduleGeneratorData);
        }
예제 #2
0
        private static ModuleResourceConverterData LoadModuleResourceConverters(int partIndex, ProtoPartSnapshot protoPartSnapshot, VesselData vesselData, Part protoPart)
        {
            var moduleResourceConverter = protoPart?.FindModulesImplementing <ModuleResourceConverter>();

            if (moduleResourceConverter is null || moduleResourceConverter.Any() == false)
            {
                return(null);
            }

            List <int> protoPartModuleSnapshotIndexes = new List <int>();
            List <ProtoPartModuleSnapshot> protoPartModuleSnapshots = new List <ProtoPartModuleSnapshot>();

            for (int i = 0; i < protoPartSnapshot.modules.Count; i++)
            {
                ProtoPartModuleSnapshot protoPartModuleSnapshot = protoPartSnapshot.modules[i];

                if (protoPartModuleSnapshot.moduleName == nameof(ModuleResourceConverter))
                {
                    protoPartModuleSnapshotIndexes.Add(i);
                    protoPartModuleSnapshots.Add(protoPartModuleSnapshot);
                }
            }

            var resourceConverterData = new ModuleResourceConverterData
            {
                PartIndex                      = partIndex,
                ProtoPart                      = protoPart,
                ProtoPartSnapshot              = protoPartSnapshot,
                PersistentPartId               = protoPartSnapshot.persistentId,
                ModuleResourceConverters       = moduleResourceConverter,
                ProtoPartModuleSnapshotIndexes = protoPartModuleSnapshotIndexes
            };

            // calculate tweakScale multipliers
            if (vesselData.PartSizeMultipliers.TryGetValue(protoPartSnapshot.persistentId, out double partSizeMultiplier))
            {
                var tweakScaleExponents = TweaksSaleHelper.GetTweakScaleExponents(nameof(ModuleResourceConverter));

                if (tweakScaleExponents.Exponents.TryGetValue("inputList", out double inputExponent))
                {
                    resourceConverterData.InputMultiplier = Math.Pow(partSizeMultiplier, inputExponent);
                }

                if (tweakScaleExponents.Exponents.TryGetValue("outputList", out double outExponent))
                {
                    resourceConverterData.OutputMultiplier = Math.Pow(partSizeMultiplier, outExponent);
                }

                if (tweakScaleExponents.Exponents.TryGetValue("reqList", out double reqExponent))
                {
                    resourceConverterData.ReqMultiplier = Math.Pow(partSizeMultiplier, reqExponent);
                }
            }

            // readout persistent data
            for (int i = 0; i < moduleResourceConverter.Count; i++)
            {
                ModuleResourceConverter resourceConverter       = moduleResourceConverter[i];
                ProtoPartModuleSnapshot protoPartModuleSnapshot = protoPartModuleSnapshots[protoPartModuleSnapshotIndexes[i]];

                resourceConverter.IsActivated     = bool.Parse(protoPartModuleSnapshot.moduleValues.GetValue(nameof(resourceConverter.IsActivated)));
                resourceConverter.EfficiencyBonus = float.Parse(protoPartModuleSnapshot.moduleValues.GetValue(nameof(resourceConverter.EfficiencyBonus)));
            }

            vesselData.ResourceConverters.Add(protoPartSnapshot.persistentId, resourceConverterData);

            return(resourceConverterData);
        }
예제 #3
0
        private static void LoadTweakScalePartModules(ProtoPartSnapshot protoPartSnapshot, VesselData vesselData)
        {
            ProtoPartModuleSnapshot protoPartModuleSnapshot = protoPartSnapshot.FindModule("TweakScale");

            if (protoPartModuleSnapshot == null)
            {
                return;
            }

            double.TryParse(protoPartModuleSnapshot.moduleValues.GetValue("currentScale"), out double currentScale);
            double.TryParse(protoPartModuleSnapshot.moduleValues.GetValue("defaultScale"), out double defaultScale);

            double tweakScalePartMultiplier = defaultScale > 0 && currentScale > 0 ? currentScale / defaultScale : 1;

            vesselData.PartSizeMultipliers.Add(protoPartSnapshot.persistentId, tweakScalePartMultiplier);
        }
예제 #4
0
        private static SolarPanelData LoadModuleDeployableSolarPanel(int partIndex, ProtoPartSnapshot protoPartSnapshot, VesselData vesselData, Part protoPart)
        {
            var moduleDeployableSolarPanels = protoPart?.FindModulesImplementing <ModuleDeployableSolarPanel>();

            if (moduleDeployableSolarPanels is null || moduleDeployableSolarPanels.Any() == false)
            {
                return(null);
            }

            List <ProtoPartModuleSnapshot> protoPartModuleSnapshots = protoPartSnapshot.modules.Where(m => m.moduleName == nameof(ModuleDeployableSolarPanel)).ToList();

            var solarPanelData = new SolarPanelData
            {
                PartIndex                   = partIndex,
                ProtoPart                   = protoPart,
                ProtoPartSnapshot           = protoPartSnapshot,
                PersistentPartId            = protoPartSnapshot.persistentId,
                ProtoPartModuleSnapshots    = protoPartModuleSnapshots,
                ModuleDeployableSolarPanels = moduleDeployableSolarPanels
            };

            // calculate tweakScale multiplier
            if (vesselData.PartSizeMultipliers.TryGetValue(protoPartSnapshot.persistentId, out double partSizeMultiplier))
            {
                double?tweakScaleExponent = TweaksSaleHelper.GetTweakScaleExponent(nameof(ModuleDeployableSolarPanel), "chargeRate");

                if (tweakScaleExponent != null)
                {
                    solarPanelData.ChargeRateMultiplier = Math.Pow(partSizeMultiplier, tweakScaleExponent.Value);
                }
            }

            for (int i = 0; i < moduleDeployableSolarPanels.Count; i++)
            {
                var moduleDeployableSolarPanel = moduleDeployableSolarPanels[i];
                var protoPartModuleSnapshot    = protoPartModuleSnapshots[i];

                moduleDeployableSolarPanel.deployState = (ModuleDeployablePart.DeployState)Enum.Parse(typeof(ModuleDeployablePart.DeployState), protoPartModuleSnapshot.moduleValues.GetValue(nameof(moduleDeployableSolarPanel.deployState)));
            }

            // store data
            vesselData.SolarPanels.Add(protoPartSnapshot.persistentId, solarPanelData);

            return(solarPanelData);
        }
예제 #5
0
        private static void LoadUnloadedPart(int partIndex, ProtoPartSnapshot protoPartSnapshot, VesselData vesselData)
        {
            LoadTweakScalePartModules(protoPartSnapshot, vesselData);

            Part protoPart = PartLoader.getPartInfoByName(protoPartSnapshot.partName)?.partPrefab;

            if (protoPart == null)
            {
                return;
            }

            LoadModuleDeployableSolarPanel(partIndex, protoPartSnapshot, vesselData, protoPart);

            LoadModuleGenerator(partIndex, protoPartSnapshot, vesselData, protoPart);

            LoadModuleResourceConverters(partIndex, protoPartSnapshot, vesselData, protoPart);

            EngineBackgroundProcessing.LoadPersistentEngine(partIndex, protoPartSnapshot, vesselData, protoPart);
        }
예제 #6
0
        void FixedUpdate()
        {
            // store info for oldest unloaded vessel
            double     last_time = 0.0;
            VesselData last_vd   = null;

            UniversalTime = Planetarium.GetUniversalTime();

            foreach (Vessel vessel in FlightGlobals.Vessels)
            {
                // don't process a vessel until unloaded, but add it to vesselDataDict
                if (vessel.loaded)
                {
                    if (!VesselDataDict.ContainsKey(vessel.id))
                    {
                        VesselDataDict.Add(vessel.id, new VesselData(vessel));
                    }

                    continue;
                }

                // ignore Kerbals
                if (vessel.isEVA)
                {
                    continue;
                }

                // ignore irrelevant vessel types
                if (vessel.vesselType == VesselType.Debris ||
                    vessel.vesselType == VesselType.Flag ||
                    vessel.vesselType == VesselType.SpaceObject ||
                    vessel.vesselType == VesselType.DeployedSciencePart ||
                    vessel.vesselType == VesselType.DeployedScienceController
                    )
                {
                    continue;
                }

                // lookup cashed vessel data
                if (!VesselDataDict.TryGetValue(vessel.id, out VesselData vesselData))
                {
                    vesselData = new VesselData(vessel);
                    VesselDataDict.Add(vessel.id, vesselData);
                }
                else
                {
                    vesselData.Vessel = vessel;
                }

                vesselData.Time += TimeWarp.fixedDeltaTime;

                // maintain oldest entry
                if (vesselData.Time > last_time)
                {
                    last_time = vesselData.Time;
                    last_vd   = vesselData;
                }

                // determine available resources and total vessel mass
                UnityEngine.Profiling.Profiler.BeginSample("PersistentThrust.PersistentScenarioModule.FixedUpdate.UpdateUnloadedVesselData");
                vesselData.UpdateUnloadedVesselData();
                UnityEngine.Profiling.Profiler.EndSample();
            }

            // at most one vessel gets background processing per physics tick :
            // if there is a vessel that is not the currently loaded vessel, then
            // we will update the vessel whose most recent background update is the oldest
            if (last_vd != null)
            {
                last_vd.DeltaTime = last_time;

                // look for relevant modules in all vessel parts
                UnityEngine.Profiling.Profiler.BeginSample("PersistentThrust.PersistentScenarioModule.FixedUpdate.LoadUnloadedParts");
                LoadUnloadedParts(last_vd);
                UnityEngine.Profiling.Profiler.EndSample();

                // extract resources from Solar Panels
                UnityEngine.Profiling.Profiler.BeginSample("PersistentThrust.PersistentScenarioModule.FixedUpdate.ProcessUnloadedSolarPanels");
                ProcessUnloadedSolarPanels(last_vd);
                UnityEngine.Profiling.Profiler.EndSample();

                // extract resources from generators (RTG etc)
                UnityEngine.Profiling.Profiler.BeginSample("PersistentThrust.PersistentScenarioModule.FixedUpdate.ProcessUnloadedModuleGenerators");
                ProcessUnloadedModuleGenerators(last_vd, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

                // extract resources from generators (Fuel Cells etc)
                UnityEngine.Profiling.Profiler.BeginSample("PersistentThrust.PersistentScenarioModule.FixedUpdate.ProcessUnloadedResourceConverters");
                ProcessUnloadedResourceConverters(last_vd, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

                // process persistent engines
                UnityEngine.Profiling.Profiler.BeginSample("PersistentThrust.PersistentScenarioModule.FixedUpdate.ProcessUnloadedPersistentEngines");
                EngineBackgroundProcessing.ProcessUnloadedPersistentEngines(last_vd, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

                // update resources on vessel
                UnityEngine.Profiling.Profiler.BeginSample("PersistentThrust.PersistentScenarioModule.FixedUpdate.UpdatePersistentResources");
                UpdatePersistentResources(last_vd, last_time);
                UnityEngine.Profiling.Profiler.EndSample();

                last_vd.Time = 0.0;
            }
        }
예제 #7
0
        private static void ProcessUnloadedResourceConverters(VesselData vesselData, double elapsedTime)
        {
            if (DetectKerbalism.Found)
            {
                return;
            }

            foreach (KeyValuePair <uint, ModuleResourceConverterData> keyValuePair in vesselData.ResourceConverters)
            {
                ModuleResourceConverterData resourceConverterData = keyValuePair.Value;
                resourceConverterData.ProtoPartSnapshot = vesselData.Vessel.protoVessel.protoPartSnapshots[resourceConverterData.PartIndex];

                for (var i = 0; i < resourceConverterData.ModuleResourceConverters.Count; i++)
                {
                    ModuleResourceConverter resourceConverter = resourceConverterData.ModuleResourceConverters[i];

                    // load protoPartModuleSnapshot
                    var moduleIndex = resourceConverterData.ProtoPartModuleSnapshotIndexes[i];
                    ProtoPartModuleSnapshot protoPartModuleSnapshot = resourceConverterData.ProtoPartSnapshot.modules[moduleIndex];

                    // read persistent IsActivated setting
                    bool.TryParse(protoPartModuleSnapshot.moduleValues.GetValue(nameof(resourceConverter.IsActivated)), out resourceConverter.IsActivated);
                    if (resourceConverter.IsActivated == false)
                    {
                        continue;
                    }

                    // read persistent EfficiencyBonus setting
                    float.TryParse(protoPartModuleSnapshot.moduleValues.GetValue(nameof(resourceConverter.EfficiencyBonus)), out resourceConverter.EfficiencyBonus);
                    if (resourceConverter.EfficiencyBonus <= 0)
                    {
                        continue;
                    }

                    // determine processRatio ratio
                    double processRatio = 1;

                    // check if we meet the requirements
                    foreach (var resourceRatio in resourceConverter.Recipe.Requirements)
                    {
                        vesselData.AvailableResources.TryGetValue(resourceRatio.ResourceName, out double availableAmount);

                        if (availableAmount < resourceRatio.Ratio * resourceConverterData.ReqMultiplier)
                        {
                            processRatio = 0;
                            break;
                        }
                    }

                    if (processRatio <= 0)
                    {
                        continue;
                    }

                    // check if we meet the output storage
                    foreach (ResourceRatio resourceRatio in resourceConverter.Recipe.Outputs)
                    {
                        if (resourceRatio.DumpExcess)
                        {
                            continue;
                        }

                        vesselData.AvailableStorage.TryGetValue(resourceRatio.ResourceName, out double availableStorage);

                        double requestedRate = resourceConverter.EfficiencyBonus * resourceRatio.Ratio * elapsedTime * resourceConverterData.OutputMultiplier;
                        double spaceRatio    = resourceRatio.Ratio > 0 ? Math.Min(1, availableStorage / requestedRate) : 1;

                        if (spaceRatio < processRatio)
                        {
                            processRatio = spaceRatio;
                        }
                    }

                    if (processRatio <= 0)
                    {
                        continue;
                    }

                    // check if we meet the input
                    foreach (ResourceRatio resourceRatio in resourceConverter.Recipe.Inputs)
                    {
                        vesselData.AvailableResources.TryGetValue(resourceRatio.ResourceName, out double availableAmount);

                        double requestedRate = resourceConverter.EfficiencyBonus * resourceRatio.Ratio * elapsedTime * resourceConverterData.InputMultiplier;
                        double foundRatio    = requestedRate > 0 ? Math.Min(1, availableAmount / requestedRate) : 1;

                        if (foundRatio < processRatio)
                        {
                            processRatio = foundRatio;
                        }
                    }

                    if (processRatio <= 0)
                    {
                        continue;
                    }

                    // extract resource from available resources
                    foreach (ResourceRatio inputResource in resourceConverter.Recipe.Inputs)
                    {
                        double resourceChange = -inputResource.Ratio * resourceConverter.EfficiencyBonus * processRatio;

                        vesselData.UpdateAvailableResource(inputResource.ResourceName, resourceChange);
                        vesselData.ResourceChange(inputResource.ResourceName, resourceChange);
                    }

                    // generate resources
                    foreach (ResourceRatio outputResource in resourceConverter.Recipe.Outputs)
                    {
                        double resourceChange = outputResource.Ratio * resourceConverter.EfficiencyBonus * processRatio;

                        vesselData.UpdateAvailableResource(outputResource.ResourceName, resourceChange);
                        vesselData.ResourceChange(outputResource.ResourceName, resourceChange);
                    }
                }
            }
        }
예제 #8
0
        private static void ProcessUnloadedModuleGenerators(VesselData vesselData, double elapsedTime)
        {
            if (DetectKerbalism.Found)
            {
                return;
            }

            foreach (KeyValuePair <uint, ModuleGeneratorData> keyValuePair in vesselData.Generators)
            {
                ModuleGeneratorData generatorData = keyValuePair.Value;
                generatorData.ProtoPartSnapshot = vesselData.Vessel.protoVessel.protoPartSnapshots[generatorData.PartIndex];

                for (var i = 0; i < generatorData.ModuleGenerators.Count; i++)
                {
                    ModuleGenerator moduleGenerator = generatorData.ModuleGenerators[i];

                    // load protoPartModuleSnapshot
                    var moduleIndex = generatorData.ProtoPartModuleSnapshotIndexes[i];
                    ProtoPartModuleSnapshot protoPartModuleSnapshot = generatorData.ProtoPartSnapshot.modules[moduleIndex];

                    // refresh persistent setting generatorIsActive
                    moduleGenerator.generatorIsActive = bool.Parse(protoPartModuleSnapshot.moduleValues.GetValue(nameof(moduleGenerator.generatorIsActive)));
                    if (moduleGenerator.generatorIsActive == false)
                    {
                        continue;
                    }

                    // refresh persistent setting throttle
                    moduleGenerator.throttle = float.Parse(protoPartModuleSnapshot.moduleValues.GetValue(nameof(moduleGenerator.throttle)));
                    if (moduleGenerator.throttle <= 0)
                    {
                        continue;
                    }

                    // determine found ratio
                    double finalFoundRatio = 1;
                    foreach (ModuleResource moduleResource in moduleGenerator.resHandler.inputResources)
                    {
                        vesselData.AvailableResources.TryGetValue(moduleResource.name, out double availableAmount);

                        double requestedRate = moduleGenerator.throttle * moduleResource.rate * elapsedTime * generatorData.InputMultiplier;
                        double foundRatio    = requestedRate > 0 ? Math.Min(1, availableAmount / requestedRate) : 1;

                        if (foundRatio < finalFoundRatio)
                        {
                            finalFoundRatio = foundRatio;
                        }
                    }

                    if (finalFoundRatio <= 0)
                    {
                        continue;
                    }

                    // extract resource from available resources
                    foreach (ModuleResource inputResource in moduleGenerator.resHandler.inputResources)
                    {
                        double resourceChange = -inputResource.rate * moduleGenerator.throttle * finalFoundRatio * generatorData.InputMultiplier;

                        vesselData.UpdateAvailableResource(inputResource.name, resourceChange);
                        vesselData.ResourceChange(inputResource.name, resourceChange);
                    }

                    // generate resources
                    foreach (ModuleResource outputResource in moduleGenerator.resHandler.outputResources)
                    {
                        double resourceChange = outputResource.rate * moduleGenerator.throttle * finalFoundRatio * generatorData.OutputMultiplier;

                        vesselData.UpdateAvailableResource(outputResource.name, resourceChange);
                        vesselData.ResourceChange(outputResource.name, resourceChange);
                    }
                }
            }
        }
        public static PersistentEngineData LoadPersistentEngine(int partIndex, ProtoPartSnapshot protoPartSnapshot,
                                                                VesselData vesselData, Part protoPart)
        {
            var persistentEngine = protoPart?.FindModuleImplementing <PersistentEngine>();

            if (persistentEngine is null)
            {
                return(null);
            }

            // find ProtoPartModuleSnapshot and moduleIndex
            int moduleIndex;
            ProtoPartModuleSnapshot persistentEngineModuleSnapshot = null;

            for (moduleIndex = 0; moduleIndex < protoPartSnapshot.modules.Count; moduleIndex++)
            {
                persistentEngineModuleSnapshot = protoPartSnapshot.modules[moduleIndex];
                if (persistentEngineModuleSnapshot.moduleName == nameof(PersistentEngine))
                {
                    break;
                }
            }

            if (persistentEngineModuleSnapshot == null)
            {
                return(null);
            }

            var engineData = new PersistentEngineData
            {
                PartIndex               = partIndex,
                ModuleIndex             = moduleIndex,
                ProtoPart               = protoPart,
                ProtoPartSnapshot       = protoPartSnapshot,
                PersistentPartId        = protoPartSnapshot.persistentId,
                ProtoPartModuleSnapshot = persistentEngineModuleSnapshot,
                PersistentEngine        = persistentEngine
            };

            // store data
            vesselData.Engines.Add(protoPartSnapshot.persistentId, engineData);

            // Load persistentThrust from ProtoPartModuleSnapshots
            persistentEngineModuleSnapshot.moduleValues.TryGetValue(nameof(persistentEngine.persistentThrust),
                                                                    ref persistentEngine.persistentThrust);

            var moduleEngines = protoPart.FindModulesImplementing <ModuleEngines>();

            if (moduleEngines == null || moduleEngines.Any() == false)
            {
                return(null);
            }

            // collect propellant configurations
            var persistentEngineModules = new List <PersistentEngineModule>();

            foreach (var moduleEngine in moduleEngines)
            {
                engineData.MaxThrust += moduleEngine.maxThrust;

                List <PersistentPropellant> persistentPropellants = PersistentPropellant.MakeList(moduleEngine.propellants);

                var persistentEngineModule = new PersistentEngineModule
                {
                    propellants    = persistentPropellants,
                    averageDensity = persistentPropellants.AverageDensity()
                };
                persistentEngineModules.Add(persistentEngineModule);
            }

            persistentEngine.moduleEngines = persistentEngineModules.ToArray();

            // check if there any active persistent engines that need to be processed
            if (persistentEngine.persistentThrust > 0)
            {
                vesselData.HasAnyActivePersistentEngine = true;
            }
            else
            {
                return(null);
            }

            return(engineData);
        }