Example #1
0
        /// <summary>
        /// Creates a new asteroid from the specific asteroid set. The asteroid will be given
        /// appropriate properties as specified in the set's config node, and added to the game as
        /// an untracked object.
        /// </summary>
        /// <remarks>Based heavily on Kopernicus's <c>DiscoverableObjects.SpawnAsteroid</c> by
        /// ThomasKerman. Thanks for reverse-engineering everything!</remarks>
        ///
        /// <param name="group">The set to which the asteroid belongs.</param>
        /// <returns>The asteroid that was added.</returns>
        ///
        /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot
        /// generate valid data. The program state will be unchanged in the event of an
        /// exception.</exception>
        /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> is
        /// null.</exception>
        private ProtoVessel spawnAsteroid(AsteroidSet group)
        {
            Orbit  orbit = makeOrbit(group);
            string name  = makeName(group);
            UntrackedObjectClass size = group.drawAsteroidSize();

            ConfigNode [] partList   = makeAsteroidParts(group);
            ConfigNode [] extraNodes = new ConfigNode []
            {
                new ConfigNode("ACTIONGROUPS"),
                makeDiscoveryInfo(group, size),
                makeVesselModules(group, partList, size),
            };

            // Stock spawner reports its module name, so do the same for custom spawns
            Debug.Log($"[{GetType ().Name}]: "
                      + Localizer.Format("#autoLOC_CustomAsteroids_LogSpawn", name, group));

            ConfigNode vessel = ProtoVessel.CreateVesselNode(name, VesselType.SpaceObject, orbit,
                                                             0, partList, extraNodes);

            ProtoVessel newVessel = HighLogic.CurrentGame.AddVessel(vessel);

            // For some reason you can always retrieve a CometVessel for any Vessel; check parts instead
            if (isComet(partList))
            {
                GameEvents.onCometSpawned.Fire(newVessel.vesselRef);
            }
            else
            {
                GameEvents.onAsteroidSpawned.Fire(newVessel.vesselRef);
            }
            return(newVessel);
        }
Example #2
0
        /// <summary>
        /// Generates tracking station info appropriate for the chosen set.
        /// </summary>
        ///
        /// <param name="group">The set to which the asteroid belongs.</param>
        /// <param name="size">The asteroid's size class.</param>
        /// <returns>A ConfigNode storing the asteroid's DiscoveryInfo object.</returns>
        ///
        /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot
        /// generate valid data. The program state will be unchanged in the event of an
        /// exception.</exception>
        /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> is
        /// null.</exception>
        private static ConfigNode makeDiscoveryInfo(AsteroidSet group, UntrackedObjectClass size)
        {
            Tuple <double, double> lifetimes    = group.drawTrackingTime();
            ConfigNode             trackingInfo = ProtoVessel.CreateDiscoveryNode(
                DiscoveryLevels.Presence, size, lifetimes.Item1, lifetimes.Item2);

            return(trackingInfo);
        }
Example #3
0
        private ConfigNode createAnomalyVessel(WBISpaceAnomaly anomaly)
        {
            // Generate vessel name
            string vesselName = DiscoverableObjectsUtil.GenerateAsteroidName();
            string prefix     = Localizer.Format("#autoLOC_6001923");

            prefix     = prefix.Replace(" <<1>>", "");
            vesselName = vesselName.Replace(prefix, "UNK-");
            vesselName = vesselName.Replace("- ", "-");

            // Generate orbit
            Orbit orbit = generateOrbit(anomaly);

            // Create part nodes
            ConfigNode[] partNodes = new ConfigNode[] { ProtoVessel.CreatePartNode(anomaly.partName, 0) };

            // Determine lifetime
            double minLifetime = anomaly.minLifetime;
            double maxLifetime = anomaly.maxLifetime;

            if (minLifetime < 0)
            {
                minLifetime = double.MaxValue;
                maxLifetime = double.MaxValue;
            }

            // Setup object class
            UntrackedObjectClass objectClass = UntrackedObjectClass.A;

            Enum.TryParse(anomaly.sizeClass, out objectClass);

            // Create discovery and additional nodes.
            ConfigNode discoveryNode = ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Presence, objectClass, minLifetime, maxLifetime);

            ConfigNode[] additionalNodes = new ConfigNode[] { new ConfigNode("ACTIONGROUPS"), discoveryNode };

            // Create vessel node
            ConfigNode vesselNode = ProtoVessel.CreateVesselNode(vesselName, VesselType.SpaceObject, orbit, 0, partNodes, additionalNodes);

            // Add vessel node to the game.
            HighLogic.CurrentGame.AddVessel(vesselNode);

            // Get vessel ID
            if (vesselNode.HasValue("persistentId"))
            {
                anomaly.vesselId = vesselNode.GetValue("persistentId");
            }

            return(vesselNode);
        }
        /// <summary>
        /// Generates tracking station info appropriate for the chosen set.
        /// </summary>
        ///
        /// <param name="group">The set to which the asteroid belongs.</param>
        /// <returns>A ConfigNode storing the asteroid's DiscoveryInfo object.</returns>
        ///
        /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot
        /// generate valid data. The program state will be unchanged in the event of an
        /// exception.</exception>
        /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> is
        /// null.</exception>
        private static ConfigNode makeDiscoveryInfo(AsteroidSet group)
        {
            Pair <float, float> trackTimes = AsteroidManager.getOptions().getUntrackedTimes();
            double lifetime = UnityEngine.Random.Range(trackTimes.first, trackTimes.second)
                              * SECONDS_PER_EARTH_DAY;
            double maxLifetime        = trackTimes.second * SECONDS_PER_EARTH_DAY;
            UntrackedObjectClass size = (UntrackedObjectClass)(int)
                                        (stockSizeCurve.Evaluate(UnityEngine.Random.Range(0.0f, 1.0f))
                                         * Enum.GetNames(typeof(UntrackedObjectClass)).Length);
            ConfigNode trackingInfo = ProtoVessel.CreateDiscoveryNode(
                DiscoveryLevels.Presence, size, lifetime, maxLifetime);

            return(trackingInfo);
        }
Example #5
0
        public void SpawnAsteroid(Asteroid asteroid, UInt32 seed)
        {
            // Create Default Orbit
            Orbit         orbit = null;
            CelestialBody body  = null;

            // Select Orbit Type
            Int32 type = Random.Range(0, 3);

            if (type == 0 && asteroid.Location.Around.Count != 0)
            {
                // Around
                Location.AroundLoader[] around = GetProbabilityList(asteroid.Location.Around,
                                                                    asteroid.Location.Around.Select(a => a.Probability.Value).ToList()).ToArray();
                Location.AroundLoader loader = around[Random.Range(0, around.Length)];
                body = UBI.GetBody(loader.Body);
                if (!body)
                {
                    return;
                }

                if (loader.Reached && !ReachedBody(body))
                {
                    return;
                }

                orbit = new Orbit
                {
                    referenceBody       = body,
                    eccentricity        = loader.Eccentricity,
                    semiMajorAxis       = loader.SemiMajorAxis,
                    inclination         = loader.Inclination,
                    LAN                 = loader.LongitudeOfAscendingNode,
                    argumentOfPeriapsis = loader.ArgumentOfPeriapsis,
                    meanAnomalyAtEpoch  = loader.MeanAnomalyAtEpoch,
                    epoch               = loader.Epoch
                };
                orbit.Init();
            }
            else if (type == 1 && asteroid.Location.Nearby.Count != 0)
            {
                // Nearby
                Location.NearbyLoader[] nearby = GetProbabilityList(asteroid.Location.Nearby,
                                                                    asteroid.Location.Nearby.Select(a => a.Probability.Value).ToList()).ToArray();
                Location.NearbyLoader loader = nearby[Random.Range(0, nearby.Length)];
                body = UBI.GetBody(loader.Body);
                if (!body)
                {
                    return;
                }

                if (loader.Reached && !ReachedBody(body))
                {
                    return;
                }

                orbit = new Orbit
                {
                    eccentricity        = body.orbit.eccentricity + loader.Eccentricity,
                    semiMajorAxis       = body.orbit.semiMajorAxis * loader.SemiMajorAxis,
                    inclination         = body.orbit.inclination + loader.Inclination,
                    LAN                 = body.orbit.LAN * loader.LongitudeOfAscendingNode,
                    argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * loader.ArgumentOfPeriapsis,
                    meanAnomalyAtEpoch  = body.orbit.meanAnomalyAtEpoch * loader.MeanAnomalyAtEpoch,
                    epoch               = body.orbit.epoch,
                    referenceBody       = body.orbit.referenceBody
                };
                orbit.Init();
            }
            else if (type == 2 && asteroid.Location.Flyby.Count != 0)
            {
                // Flyby
                Location.FlybyLoader[] flyby = GetProbabilityList(asteroid.Location.Flyby,
                                                                  asteroid.Location.Flyby.Select(a => a.Probability.Value).ToList()).ToArray();
                Location.FlybyLoader loader = flyby[Random.Range(0, flyby.Length)];
                body = UBI.GetBody(loader.Body);
                if (!body)
                {
                    return;
                }

                if (loader.Reached && !ReachedBody(body))
                {
                    return;
                }

                orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(loader.MinDuration, loader.MaxDuration));
            }

            // Check
            if (orbit == null)
            {
                Debug.Log("[Kopernicus] No new objects this time. (Probability is " + asteroid.Probability.Value + "%)");
                return;
            }

            // Name
            String asteroidName = DiscoverableObjectsUtil.GenerateAsteroidName();

            // Lifetime
            Double lifetime    = Random.Range(asteroid.MinUntrackedLifetime, asteroid.MaxUntrackedLifetime) * 24d * 60d * 60d;
            Double maxLifetime = asteroid.MaxUntrackedLifetime * 24d * 60d * 60d;

            // Size
            UntrackedObjectClass size = (UntrackedObjectClass)(Int32)(asteroid.Size.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length);

            // Spawn
            ConfigNode vessel = null;

            vessel = ProtoVessel.CreateVesselNode(
                asteroidName,
                VesselType.SpaceObject,
                orbit,
                0,
                new[]
            {
                ProtoVessel.CreatePartNode(
                    "PotatoRoid",
                    seed
                    )
            },
                new ConfigNode("ACTIONGROUPS"),
                ProtoVessel.CreateDiscoveryNode(
                    DiscoveryLevels.Presence,
                    size,
                    lifetime,
                    maxLifetime
                    )
                );
            OverrideNode(ref vessel, asteroid.Vessel);
            ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame);

            if (asteroid.UniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0)
            {
                return;
            }

            Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel);
            protoVessel.Load(HighLogic.CurrentGame.flightState);
            GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef);
            GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef);
            Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!");
        }
Example #6
0
        public void SpawnAsteroid(Asteroid asteroid, UInt32 seed)
        {
            // Create Default Orbit
            Orbit         orbit = null;
            CelestialBody body  = null;

            // Select Orbit Type
            Int32 type = Random.Range(0, 3);

            if (type == 0 && asteroid.Location.Around.Count != 0)
            {
                // Around
                Location.AroundLoader[] around = GetProbabilityList(asteroid.Location.Around,
                                                                    asteroid.Location.Around.Select(a => a.Probability.Value).ToList()).ToArray();
                Location.AroundLoader loader = around[Random.Range(0, around.Length)];
                body = UBI.GetBody(loader.Body);
                if (!body)
                {
                    return;
                }

                if (loader.Reached && !ReachedBody(body))
                {
                    return;
                }

                orbit = new Orbit
                {
                    referenceBody       = body,
                    eccentricity        = loader.Eccentricity,
                    semiMajorAxis       = loader.SemiMajorAxis,
                    inclination         = loader.Inclination,
                    LAN                 = loader.LongitudeOfAscendingNode,
                    argumentOfPeriapsis = loader.ArgumentOfPeriapsis,
                    meanAnomalyAtEpoch  = loader.MeanAnomalyAtEpoch,
                    epoch               = loader.Epoch
                };
                orbit.Init();
            }
            else if (type == 1 && asteroid.Location.Nearby.Count != 0)
            {
                // Nearby
                Location.NearbyLoader[] nearby = GetProbabilityList(asteroid.Location.Nearby,
                                                                    asteroid.Location.Nearby.Select(a => a.Probability.Value).ToList()).ToArray();
                Location.NearbyLoader loader = nearby[Random.Range(0, nearby.Length)];
                body = UBI.GetBody(loader.Body);
                if (!body)
                {
                    return;
                }

                if (loader.Reached && !ReachedBody(body))
                {
                    return;
                }

                orbit = new Orbit
                {
                    eccentricity        = body.orbit.eccentricity + loader.Eccentricity,
                    semiMajorAxis       = body.orbit.semiMajorAxis * loader.SemiMajorAxis,
                    inclination         = body.orbit.inclination + loader.Inclination,
                    LAN                 = body.orbit.LAN * loader.LongitudeOfAscendingNode,
                    argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * loader.ArgumentOfPeriapsis,
                    meanAnomalyAtEpoch  = body.orbit.meanAnomalyAtEpoch * loader.MeanAnomalyAtEpoch,
                    epoch               = body.orbit.epoch,
                    referenceBody       = body.orbit.referenceBody
                };
                orbit.Init();
            }
            else if (type == 2 && asteroid.Location.Flyby.Count != 0)
            {
                // Flyby
                Location.FlybyLoader[] flyby = GetProbabilityList(asteroid.Location.Flyby,
                                                                  asteroid.Location.Flyby.Select(a => a.Probability.Value).ToList()).ToArray();
                Location.FlybyLoader loader = flyby[Random.Range(0, flyby.Length)];
                body = UBI.GetBody(loader.Body);
                if (!body)
                {
                    return;
                }

                if (loader.Reached && !ReachedBody(body))
                {
                    return;
                }

                orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(loader.MinDuration, loader.MaxDuration));
            }

            // Check
            if (orbit == null)
            {
                Debug.Log("[Kopernicus] No new objects this time. (Probability is " + asteroid.Probability.Value + "%)");
                return;
            }

            // Name
            String asteroidName = DiscoverableObjectsUtil.GenerateAsteroidName();

            // Lifetime
            Double lifetime    = Random.Range(asteroid.MinUntrackedLifetime, asteroid.MaxUntrackedLifetime) * 24d * 60d * 60d;
            Double maxLifetime = asteroid.MaxUntrackedLifetime * 24d * 60d * 60d;

            // Size
            UntrackedObjectClass size = (UntrackedObjectClass)(Int32)(asteroid.Size.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length);

            // Spawn
            ConfigNode vessel = null;

#if (KSP_VERSION_1_10_1 || KSP_VERSION_1_11_1)
            if (Random.Range(0, 100) > RuntimeUtility.KopernicusConfig.CometPercentage)
            {
#endif
            vessel = ProtoVessel.CreateVesselNode(
                asteroidName,
                VesselType.SpaceObject,
                orbit,
                0,
                new[]
            {
                ProtoVessel.CreatePartNode(
                    "PotatoRoid",
                    seed
                    )
            },
                new ConfigNode("ACTIONGROUPS"),
                ProtoVessel.CreateDiscoveryNode(
                    DiscoveryLevels.Presence,
                    size,
                    lifetime,
                    maxLifetime
                    )
                );
            OverrideNode(ref vessel, asteroid.Vessel);
            ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame);
            if (asteroid.UniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0)
            {
                return;
            }

            Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel);
            protoVessel.Load(HighLogic.CurrentGame.flightState);
            GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef);
            GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef);
            Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!");
#if (KSP_VERSION_1_10_1 || KSP_VERSION_1_11_1)
        }

        else
        {
            float                fragmentDynamicPressureModifier = 0f;
            bool                 optimizedCollider = false;
            CometOrbitType       cometType         = CometManager.GenerateWeightedCometType();
            Orbit                cometOrbit        = cometType.CalculateHomeOrbit();
            UntrackedObjectClass randomObjClass    = cometType.GetRandomObjClass();
            CometDefinition      cometDef          = CometManager.GenerateDefinition(cometType, randomObjClass, (int)seed);
            ConfigNode           configNode        = cometDef.CreateVesselNode(optimizedCollider, fragmentDynamicPressureModifier, hasName: false);
            ConfigNode           configNode2       = ProtoVessel.CreatePartNode("PotatoComet", seed);
            uint                 value             = 0u;
            configNode2.TryGetValue("persistentId", ref value);
            configNode.AddValue("cometPartId", value);
            ConfigNode configNode3 = new ConfigNode("VESSELMODULES");
            configNode3.AddNode(configNode);
            vessel = ProtoVessel.CreateVesselNode(DiscoverableObjectsUtil.GenerateCometName(), VesselType.SpaceObject, cometOrbit, 0, new ConfigNode[1] {
                configNode2
            }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Presence, randomObjClass, lifetime, maxLifetime), configNode3);
            OverrideNode(ref vessel, asteroid.Vessel);
            ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame);
            Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel);
            protoVessel.Load(HighLogic.CurrentGame.flightState);
            GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef);
            GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef);
            Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!");
        }
#endif
        }
Example #7
0
        // Spawn the actual asteroid
        public void SpawnAsteroid(Asteroid asteroid, uint seed)
        {
            // Create Default Orbit
            Orbit         orbit = null;
            CelestialBody body  = null;

            // Select Orbit Type
            int type = Random.Range(0, 3);

            if (type == 0 && asteroid.location.around.Count != 0)
            {
                // Around
                IEnumerable <Location.AroundLoader> arounds = GetProbabilityList(asteroid.location.around, asteroid.location.around.Select(a => a.probability.value));
                Location.AroundLoader around = arounds.ElementAt(Random.Range(0, arounds.Count()));
                body = PSystemManager.Instance.localBodies.Find(b => b.name == around.body);
                if (!body)
                {
                    return;
                }
                if (around.reached && !ReachedBody(body))
                {
                    return;
                }
                orbit = new Orbit();
                orbit.referenceBody       = body;
                orbit.eccentricity        = around.eccentricity;
                orbit.semiMajorAxis       = around.semiMajorAxis;
                orbit.inclination         = around.inclination;
                orbit.LAN                 = around.longitudeOfAscendingNode;
                orbit.argumentOfPeriapsis = around.argumentOfPeriapsis;
                orbit.meanAnomalyAtEpoch  = around.meanAnomalyAtEpoch;
                orbit.epoch               = around.epoch;
                orbit.Init();
            }
            else if (type == 1 && asteroid.location.nearby.Count != 0)
            {
                // Nearby
                IEnumerable <Location.NearbyLoader> nearbys = GetProbabilityList(asteroid.location.nearby, asteroid.location.nearby.Select(a => a.probability.value));
                Location.NearbyLoader nearby = nearbys.ElementAt(Random.Range(0, nearbys.Count()));
                body = PSystemManager.Instance.localBodies.Find(b => b.name == nearby.body);
                if (!body)
                {
                    return;
                }
                if (nearby.reached && !ReachedBody(body))
                {
                    return;
                }
                orbit = new Orbit();
                orbit.eccentricity        = body.orbit.eccentricity + nearby.eccentricity;
                orbit.semiMajorAxis       = body.orbit.semiMajorAxis * nearby.semiMajorAxis;
                orbit.inclination         = body.orbit.inclination + nearby.inclination;
                orbit.LAN                 = body.orbit.LAN * nearby.longitudeOfAscendingNode;
                orbit.argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * nearby.argumentOfPeriapsis;
                orbit.meanAnomalyAtEpoch  = body.orbit.meanAnomalyAtEpoch * nearby.meanAnomalyAtEpoch;
                orbit.epoch               = body.orbit.epoch;
                orbit.referenceBody       = body.orbit.referenceBody;
                orbit.Init();
            }
            else if (type == 2 && asteroid.location.flyby.Count != 0)
            {
                // Flyby
                IEnumerable <Location.FlybyLoader> flybys = GetProbabilityList(asteroid.location.flyby, asteroid.location.flyby.Select(a => a.probability.value));
                Location.FlybyLoader flyby = flybys.ElementAt(Random.Range(0, flybys.Count()));
                body = PSystemManager.Instance.localBodies.Find(b => b.name == flyby.body);
                if (!body)
                {
                    return;
                }
                if (flyby.reached && !ReachedBody(body))
                {
                    return;
                }
                orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(flyby.minDuration, flyby.maxDuration));
            }

            // Check
            if (orbit == null)
            {
                Debug.Log("[Kopernicus]: No new objects this time. (Probablility is " + asteroid.probability.value + "%)");
                return;
            }

            // Name
            string name = DiscoverableObjectsUtil.GenerateAsteroidName();

            // Lifetime
            double lifetime    = Random.Range(asteroid.minUntrackedLifetime, asteroid.maxUntrackedLifetime) * 24d * 60d * 60d;
            double maxLifetime = asteroid.maxUntrackedLifetime * 24d * 60d * 60d;

            // Size
            UntrackedObjectClass size = (UntrackedObjectClass)((int)(asteroid.size.curve.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length));

            // Spawn
            ConfigNode vessel = ProtoVessel.CreateVesselNode(
                name,
                VesselType.SpaceObject,
                orbit,
                0,
                new[]
            {
                ProtoVessel.CreatePartNode(
                    "PotatoRoid",
                    seed,
                    new ProtoCrewMember[0]
                    )
            },
                new ConfigNode("ACTIONGROUPS"),
                ProtoVessel.CreateDiscoveryNode(
                    DiscoveryLevels.Presence,
                    size,
                    lifetime,
                    maxLifetime
                    )
                );

            OverrideNode(ref vessel, asteroid.vessel);
            ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame);

            if (asteroid.uniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0)
            {
                return;
            }
            protoVessel.Load(HighLogic.CurrentGame.flightState);
            GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef);
            Debug.Log("[Kopernicus]: New object found near " + body.name + ": " + protoVessel.vesselName + "!");
        }
Example #8
0
        /// <summary>
        /// Generates any vessel modules needed by a particular asteroid.
        /// </summary>
        /// <param name="group">The asteroid group to which the asteroid belongs.</param>
        /// <param name="partList">The part(s) from which the asteroid is made.</param>
        /// <param name="size">The asteroid's size class.</param>
        /// <returns>A <c>VesselModules</c> node containing all vessel modules besides
        /// the defaults (currently <c>FlightIntegrator</c> and <c>AxisGroupModule</c>).</returns>
        /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> or <c>partList</c> is
        /// null.</exception>
        /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot generate
        /// valid data, or if <c>partList</c> does not contain exactly one part, or contains an
        /// unsupported part. The program state will be unchanged in the event of an exception.</exception>
        private ConfigNode makeVesselModules(AsteroidSet group, ConfigNode[] partList, UntrackedObjectClass size)
        {
            if (partList.Length != 1)
            {
                throw new InvalidOperationException(
                          Localizer.Format("#autoLOC_CustomAsteroids_ErrorMultiParts", partList));
            }

            ConfigNode wrapper = new ConfigNode("VESSELMODULES");

            // CometVessel seems to be removed if there's no ModuleComet, but filter just in case
            if (isComet(partList))
            {
                string         cometType  = group.getCometOrbit();
                bool           cometName  = group.getUseCometName();
                CometOrbitType stockClass = CometManager.GetCometOrbitType(cometType);
                if (stockClass is null)
                {
                    throw new InvalidOperationException(Localizer.Format("#autoLOC_CustomAsteroids_ErrorNoCometType", cometType));
                }
                // As far as I can tell the object class is used to scale the activity level
                ConfigNode moduleComet = CometManager.GenerateDefinition(stockClass, size, new System.Random().Next())
                                         .CreateVesselNode(false, 0.0f, !cometName);
                wrapper.AddNode(moduleComet);
            }
            return(wrapper);
        }
	/// <summary>Updates the asteroid size</summary>
	///
	/// <param name="size">The asteroid class (A-E)</param>
	///
	public extern void SetUntrackedObjectSize (UntrackedObjectClass size);
	/// <summary>Returns asteroid size displayed in map view</summary>
	///
	/// <param name="sizeClass">The asteroid type to label</param>
	///
	/// <returns>The asteroid class printed beneath an untracked asteroid.
	///
	/// <example>"C (Medium)"</example>
	///
	/// If not a valid value of UntrackedObjectClass, returns "???"
	/// </returns>
    public static extern string GetSizeClassSizes(UntrackedObjectClass sizeClass);
	/// <summary>Returns long description of asteroid type</summary>
	///
	/// <param name="sizeClass">The asteroid type to label</param>
	///
	/// <returns>The asteroid class explanation printed on the tracking station's info panel.
	///
	/// <example>"Class C Objects are about average-sized..."</example>
	///
	/// If not a valid value of UntrackedObjectClass, returns "This seems to be a non-standard size class. Who knows what it'll look like?"
	/// </returns>
    public static extern string GetSizeClassDescription(UntrackedObjectClass sizeClass);
 /// <summary>Updates the asteroid size</summary>
 ///
 /// <param name="size">The asteroid class (A-E)</param>
 ///
 public extern void SetUntrackedObjectSize(UntrackedObjectClass size);
 /// <summary>Returns asteroid size displayed in map view</summary>
 ///
 /// <param name="sizeClass">The asteroid type to label</param>
 ///
 /// <returns>The asteroid class printed beneath an untracked asteroid.
 ///
 /// <example>"C (Medium)"</example>
 ///
 /// If not a valid value of UntrackedObjectClass, returns "???"
 /// </returns>
 public static extern string GetSizeClassSizes(UntrackedObjectClass sizeClass);
 /// <summary>Returns long description of asteroid type</summary>
 ///
 /// <param name="sizeClass">The asteroid type to label</param>
 ///
 /// <returns>The asteroid class explanation printed on the tracking station's info panel.
 ///
 /// <example>"Class C Objects are about average-sized..."</example>
 ///
 /// If not a valid value of UntrackedObjectClass, returns "This seems to be a non-standard size class. Who knows what it'll look like?"
 /// </returns>
 public static extern string GetSizeClassDescription(UntrackedObjectClass sizeClass);