コード例 #1
0
        static void ProcessFissionGenerator(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule fission_generator, Resource_info ec, double elapsed_s)
        {
            // note: ignore heat

            double power     = Lib.ReflectionValue <float>(fission_generator, "PowerGeneration");
            var    reactor   = p.modules.Find(k => k.moduleName == "FissionReactor");
            double tweakable = reactor == null ? 1.0 : Lib.ConfigValue(reactor.moduleValues, "CurrentPowerPercent", 100.0) * 0.01;

            ec.Produce(power * tweakable * elapsed_s);
        }
コード例 #2
0
        static void ProcessRadioisotopeGenerator(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule radioisotope_generator, Resource_info ec, double elapsed_s)
        {
            // note: doesn't support easy mode

            double power        = Lib.ReflectionValue <float>(radioisotope_generator, "BasePower");
            double half_life    = Lib.ReflectionValue <float>(radioisotope_generator, "HalfLife");
            double mission_time = v.missionTime / (3600.0 * Lib.HoursInDay() * Lib.DaysInYear());
            double remaining    = Math.Pow(2.0, (-mission_time) / half_life);

            ec.Produce(power * remaining * elapsed_s);
        }
コード例 #3
0
        private static void RunProcessTick(Vessel v, double elapsed_s,
                                           double ec_produced, List <KeyValuePair <string, double> > resourcesProduced,
                                           double ec_consumed, List <KeyValuePair <string, double> > resourcesConsumed,
                                           Resource_info ec, Vessel_resources resources)
        {
            // evaluate process rate
            double rate = 1;

            if (ec_consumed < ec.amount)
            {
                rate = ec.amount / ec_consumed;
            }

            foreach (var consumed in resourcesConsumed)
            {
                var ri = resources.Info(v, consumed.Key);
                rate = Math.Min(rate, Lib.Clamp(ri.amount / (consumed.Value * elapsed_s), 0, 1));
            }

            foreach (var produced in resourcesProduced)
            {
                var ri = resources.Info(v, produced.Key);
                var capacityAvailable = ri.capacity - ri.amount;
                var amountProduced    = produced.Value * elapsed_s;
                if (capacityAvailable < amountProduced)
                {
                    rate = Math.Min(rate, Lib.Clamp(capacityAvailable / amountProduced, 0, 1));
                }
            }

            // produce/consume according to rate
            if (rate < double.Epsilon)
            {
                return;
            }

            ec.Consume(ec_consumed * elapsed_s * rate, "module process");
            ec.Produce(ec_produced * elapsed_s * rate, "module process");

            foreach (var consumed in resourcesConsumed)
            {
                resources.Info(v, consumed.Key).Consume(consumed.Value * elapsed_s * rate, "module process");
            }
            foreach (var produced in resourcesProduced)
            {
                resources.Info(v, produced.Key).Produce(produced.Value * elapsed_s * rate, "module process");
            }
        }
コード例 #4
0
        static void ProcessCurvedPanel(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule curved_panel, Part part_prefab, Vessel_info info, Resource_info ec, double elapsed_s)
        {
            // note: we assume deployed, this is a current limitation

            // if in sunlight
            if (info.sunlight > double.Epsilon)
            {
                // get values from module
                string transform_name = Lib.ReflectionValue <string>(curved_panel, "PanelTransformName");
                float  tot_rate       = Lib.ReflectionValue <float>(curved_panel, "TotalEnergyRate");

                // get components
                Transform[] components = part_prefab.FindModelTransforms(transform_name);
                if (components.Length == 0)
                {
                    return;
                }

                // calculate normalized solar flux
                // note: this include fractional sunlight if integrated over orbit
                // note: this include atmospheric absorption if inside an atmosphere
                double norm_solar_flux = info.solar_flux / Sim.SolarFluxAtHome();

                // calculate rate per component
                double rate = (double)tot_rate / (double)components.Length;

                // calculate world-space part rotation quaternion
                // note: a possible optimization here is to cache the transform lookup (unity was coded by monkeys)
                Quaternion rot = v.transform.rotation * p.rotation;

                // calculate output of all components
                double output = 0.0;
                foreach (Transform t in components)
                {
                    output += rate                                                                                         // nominal rate per-component at 1 AU
                              * norm_solar_flux                                                                            // normalized solar flux at panel distance from sun
                              * Math.Max(Vector3d.Dot(info.sun_dir, (rot * t.forward).normalized), 0.0);                   // cosine factor of component orientation
                }

                // produce EC
                ec.Produce(output * elapsed_s);
            }
        }
コード例 #5
0
        static void ProcessPanel(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleDeployableSolarPanel panel, Vessel_info info, Resource_info ec, double elapsed_s)
        {
            // note: we ignore temperature curve, and make sure it is not relevant in the MM patch
            // note: cylindrical and spherical panels are not supported
            // note: we assume the tracking target is SUN
            // if in sunlight and extended
            if (info.sunlight > double.Epsilon && m.moduleValues.GetValue("deployState") == "EXTENDED")
            {
                // get panel normal/pivot direction in world space
                Transform tr  = panel.part.FindModelComponent <Transform>(panel.pivotName);
                Vector3d  dir = panel.isTracking ? tr.up : tr.forward;
                dir = (v.transform.rotation * p.rotation * dir).normalized;

                float age          = (float)(v.missionTime / (Lib.HoursInDay() * 3600));
                float effic_factor = panel.timeEfficCurve != null?panel.timeEfficCurve.Evaluate(age) : 1.0f;

                // calculate cosine factor
                // - fixed panel: clamped cosine
                // - tracking panel, tracking pivot enabled: around the pivot
                // - tracking panel, tracking pivot disabled: assume perfect alignment
                double cosine_factor =
                    !panel.isTracking
                                  ? Math.Max(Vector3d.Dot(info.sun_dir, dir), 0.0)
                                  : Settings.TrackingPivot
                                  ? Math.Cos(1.57079632679 - Math.Acos(Vector3d.Dot(info.sun_dir, dir)))
                                  : 1.0;

                // calculate normalized solar flux
                // - this include fractional sunlight if integrated over orbit
                // - this include atmospheric absorption if inside an atmosphere
                double norm_solar_flux = info.solar_flux / Sim.SolarFluxAtHome();

                // calculate output
                double output = panel.resHandler.outputResources[0].rate                              // nominal panel charge rate at 1 AU
                                * norm_solar_flux                                                     // normalized flux at panel distance from sun
                                * cosine_factor                                                       // cosine factor of panel orientation
                                * effic_factor;

                // produce EC
                ec.Produce(output * elapsed_s, "panel");
            }
        }
コード例 #6
0
        static void ProcessFNGenerator(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule fission_generator, Resource_info ec, double elapsed_s)
        {
            string maxPowerStr = Lib.Proto.GetString(m, "MaxPowerStr");
            double maxPower    = 0;

            if (maxPowerStr.Contains("GW"))
            {
                maxPower = double.Parse(maxPowerStr.Replace(" GW", "")) * 1000000;
            }
            else if (maxPowerStr.Contains("MW"))
            {
                maxPower = double.Parse(maxPowerStr.Replace(" MW", "")) * 1000;
            }
            else
            {
                maxPower = double.Parse(maxPowerStr.Replace(" KW", ""));
            }

            ec.Produce(maxPower * elapsed_s);
        }
コード例 #7
0
        public void FixedUpdate()
        {
            // do nothing in editor
            if (Lib.IsEditor())
            {
                return;
            }

            // do nothing if there isn't a solar panel
            if (panel == null)
            {
                return;
            }

            // get resource handler
            Resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

            // get vessel data from cache
            Vessel_info info = Cache.VesselInfo(vessel);

            // do nothing if vessel is invalid
            if (!info.is_valid)
            {
                return;
            }

            // detect if sunlight is evaluated analytically
            bool analytical_sunlight = info.sunlight > 0.0 && info.sunlight < 1.0;

            // detect occlusion from other vessel parts
            // - we are only interested when the sunlight evaluation is discrete
            var  collider         = panel.hit.collider;
            bool locally_occluded = !analytical_sunlight && collider != null && info.sunlight > 0.0;

            // if panel is enabled and extended, and if sun is not occluded, not even locally
            if (panel.isEnabled && panel.deployState == ModuleDeployablePart.DeployState.EXTENDED && info.sunlight > 0.0 && !locally_occluded)
            {
                // calculate cosine factor
                // - the stock module is already computing the tracking direction
                double cosine_factor = Math.Max(Vector3d.Dot(info.sun_dir, panel.trackingDotTransform.forward), 0.0);

                // calculate normalized solar flux
                // - this include fractional sunlight if integrated over orbit
                // - this include atmospheric absorption if inside an atmosphere
                double norm_solar_flux = info.solar_flux / Sim.SolarFluxAtHome();

                // calculate output
                double output = rate                                              // nominal panel charge rate at 1 AU
                                * norm_solar_flux                                 // normalized flux at panel distance from sun
                                * cosine_factor;                                  // cosine factor of panel orientation

                // produce EC
                ec.Produce(output * Kerbalism.elapsed_s, "panel");

                // update ui
                field_visibility = info.sunlight * 100.0;
                field_atmosphere = info.atmo_factor * 100.0;
                field_exposure   = cosine_factor * 100.0;
                field_output     = output;
                Fields["field_visibility"].guiActive = analytical_sunlight;
                Fields["field_atmosphere"].guiActive = info.atmo_factor < 1.0;
                Fields["field_exposure"].guiActive   = true;
                Fields["field_output"].guiActive     = true;
            }
            // if panel is disabled, retracted, or in shadow
            else
            {
                // hide ui
                Fields["field_visibility"].guiActive = false;
                Fields["field_atmosphere"].guiActive = false;
                Fields["field_exposure"].guiActive   = false;
                Fields["field_output"].guiActive     = false;
            }

            // update status ui
            field_status = analytical_sunlight
                        ? "<color=#ffff22>Integrated over the orbit</color>"
                        : locally_occluded
                        ? "<color=#ff2222>Occluded by vessel</color>"
                        : info.sunlight < 1.0
                        ? "<color=#ff2222>Occluded by celestial body</color>"
                        : string.Empty;
            Fields["field_status"].guiActive = field_status.Length > 0;
        }