/// <summary>
        /// GameEvent of any deployed science part changed in state
        /// </summary>
        protected void groundSciencePartStateChange(ModuleGroundSciencePart sciencePart)
        {
            if (sciencePart is ModuleGroundExpControl)
            {
                //toggle antenna module based on part enabled toggling
                Part controlStation = sciencePart.part;
                CNConstellationAntennaModule antennaMod = controlStation.FindModuleImplementing <CNConstellationAntennaModule>();
                if (antennaMod != null)
                {
                    antennaMod.InUse = sciencePart.Enabled;
                    //Comment: Control Station has CanComm=false at this point -> require player action
                }

                this.rebuildFreqList(true);
            }
            else if (sciencePart is ModuleGroundCommsPart)
            {
                this.rebuildFreqList(true);
            }
        }
        /// <summary>
        /// Find all Cargo parts within range, used to calculate power needs
        /// If firstTime is true, then also find the closest EVA'd kerbal and use that kerbal's stats for any adjustments
        /// The assumption is that the closest kerbal will be the one which dropped the part
        /// </summary>
        /// <param name="firstTime"></param>
        void GetCargoPartsInRange(bool firstTime = false)
        {
            numControllers = 0;
            numBatteries   = 0;

            ModuleGroundExpControl closestModuleControl = null;

            totalPowerNeeded        = 0f;
            totalPowerProduced      = 0;
            totalSolarPowerProduced = 0;
            totalBatPowerProduced   = 0;

            Vessel nearestVessel         = null;
            float  nearestVesselDistance = -1;

            foreach (Vessel v in FlightGlobals.Vessels)
            {
                if (v != null && v.Parts.Count == 1)
                {
                    var moduleControl = v.FindPartModuleImplementing <ModuleGroundExpControl>();
                    if (moduleControl != null && moduleControl.part != null)
                    {
                        float num = Vector3.Distance(base.transform.position, moduleControl.part.transform.position);
                        if (num <= moduleControl.controlUnitRange)
                        {
                            if (closestModuleControl == null)
                            {
                                closestModuleControl = moduleControl;
                            }
                            else
                            {
                                float num2 = Vector3.Distance(base.transform.position, closestModuleControl.part.transform.position);
                                if (num2 < num)
                                {
                                    closestModuleControl = moduleControl;
                                }
                            }
                            numControllers++;

                            Log.Info("Controller found, power needed: " + closestModuleControl.powerNeeded + ", experimentsConnected: " + closestModuleControl.experimentsConnected);

                            int i = closestModuleControl.powerNeeded.IndexOf(' ');

                            if (i > 0)
                            {
                                totalPowerNeeded += float.Parse(closestModuleControl.powerNeeded.Substring(0, closestModuleControl.powerNeeded.IndexOf(' ')));
                            }
                            else
                            if (closestModuleControl.powerNeeded != null && closestModuleControl.powerNeeded != "")
                            {
                                totalPowerNeeded += float.Parse(closestModuleControl.powerNeeded);
                            }
                        }
                    }

                    if (v.isEVA)
                    {
                        if (nearestVessel == null)
                        {
                            nearestVessel         = v;
                            nearestVesselDistance = Vector3.Distance(base.transform.position, v.Parts[0].transform.position);
                        }
                        else
                        {
                            float num2 = Vector3.Distance(base.transform.position, v.Parts[0].transform.position);
                            if (num2 < nearestVesselDistance)
                            {
                                nearestVessel         = v;
                                nearestVesselDistance = num2;
                            }
                        }
                    }
                }
            }

            if (closestModuleControl != null)
            {
                foreach (Vessel v in FlightGlobals.Vessels)
                {
                    if (v != null && v.Parts.Count == 1)
                    {
                        ModuleGroundSciencePart moduleSolar = v.FindPartModuleImplementing <ModuleGroundSciencePart>();
                        if (moduleSolar != null && moduleSolar.IsSolarPanel)
                        {
                            float num = Vector3.Distance(base.transform.position, moduleSolar.part.transform.position);
                            if (num <= closestModuleControl.controlUnitRange)
                            {
                                Log.Info("vessel.directSunlight: " + moduleSolar.vessel.directSunlight + ", Solar found, PowerUnitsRequired: " + moduleSolar.PowerUnitsRequired + ", PowerUnitsProduced: " + moduleSolar.PowerUnitsProduced +
                                         ", ActualPowerUnitsProduced: " + moduleSolar.ActualPowerUnitsProduced);

                                if (moduleSolar.Enabled)
                                {
                                    //
                                    // The following is designed to work around a bug
                                    // https://bugs.kerbalspaceprogram.com/issues/24349
                                    //
                                    if (TimeWarp.CurrentRate != 1)
                                    {
                                        if (moduleSolar.vessel.directSunlight)
                                        {
                                            moduleSolar.ActualPowerUnitsProduced = moduleSolar.PowerUnitsProduced;
                                        }
                                        else
                                        {
                                            moduleSolar.ActualPowerUnitsProduced = 0;
                                        }
                                    }
                                    totalSolarPowerProduced += moduleSolar.ActualPowerUnitsProduced;
                                }
                            }
                        }
                        else
                        {
                            ModuleDeployableBattery moduleBattery = v.FindPartModuleImplementing <ModuleDeployableBattery>();

                            if (moduleBattery != null && moduleBattery.IsBattery)
                            {
                                float num = Vector3.Distance(base.transform.position, moduleBattery.part.transform.position);
                                if (num <= closestModuleControl.controlUnitRange)
                                {
                                    numBatteries++;
                                    int batPowerProduced = (int)moduleBattery.maxPowerUnitsFlow;

                                    if (moduleBattery.availAmount < maxPUFlowPerDeltaTime)
                                    {
                                        batPowerProduced = 0;
                                    }
                                    totalBatPowerProduced += batPowerProduced;
                                }
                            }
                        }
                    }
                }
            }

            // There is no easy way to know which EVA'd kerbal dropped/placed this, so when created,
            // as part of the look of all vessels, find the kerbal nearest this part, and use that
            // kerbal's skill to get the effect

            if (firstTime)
            {
                if (nearestVessel != null && nearestVessel.isEVA && nearestVesselDistance < 2)
                {
                    if (nearestVessel.parts[0].protoModuleCrew[0].HasEffect <DeployedSciencePowerSkill>())
                    {
                        DeployedSciencePowerSkill effect = nearestVessel.parts[0].protoModuleCrew[0].GetEffect <DeployedSciencePowerSkill>();
                        if (effect != null)
                        {
                            kerbalEffectAdjustments    = effect.GetValue();
                            invKerbalEffectAdjustments = 1f / kerbalEffectAdjustments;
                            string msg1 = "Kerbal Effect Adjustment: " + kerbalEffectAdjustments + ", Description: " + Localizer.Format("#autoLOC_8002229", effect.GetValue());
                            string msg2 = ("MaxValue: " + ((solarPanelChargeRate / kerbalEffectAdjustments) * part.Resources[power].amount).ToString("F2"));

                            Log.Info(msg1);
                            Log.Info(msg2);
                            ScreenMessages.PostScreenMessage(msg1, 10, ScreenMessageStyle.UPPER_CENTER);
                            ScreenMessages.PostScreenMessage(msg2, 10, ScreenMessageStyle.UPPER_CENTER);
                        }
                    }
                }
            }
            Log.Info("totalPowerNeeded: " + totalPowerNeeded + ", totalPowerProduced: " + totalPowerProduced);
        }