コード例 #1
0
        /// <summary>
        /// Generates a new asteroid name appropriate for the chosen set.
        /// </summary>
        ///
        /// <param name="group">The set to which the asteroid belongs.</param>
        /// <returns>A randomly generated name. The name will be prefixed by a population-specific
        /// name if custom names are enabled, or by "Ast." if they are disabled.</returns>
        ///
        /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot
        /// generate valid names. 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 string makeName(AsteroidSet group)
        {
            string name = DiscoverableObjectsUtil.GenerateAsteroidName();

            if (AsteroidManager.getOptions().getRenameOption())
            {
                GroupCollection parsed = astName.Match(name).Groups;
                if (parsed [0].Success)
                {
                    string newBase = group.getAsteroidName();
                    if (!newBase.Contains("<<1>>"))
                    {
                        newBase += " <<1>>";
                    }
                    string id = parsed ["id"].ToString();
                    name = Localizer.Format(newBase, id);
                }
                // if asteroid name doesn't match expected format, leave it as-is
#if DEBUG
                Debug.Log("[CustomAsteroids]: "
                          + Localizer.Format("#autoLOC_CustomAsteroids_LogRename", name));
#endif
            }

            return(name);
        }
コード例 #2
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);
        }
コード例 #3
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);
        }
コード例 #4
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);
        }
コード例 #5
0
        /// <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);
        }
コード例 #6
0
        /// <summary>
        /// Generates vessel parts and resources appropriate for the chosen set.
        /// </summary>
        ///
        /// <param name="group">The set to which the asteroid belongs.</param>
        /// <returns>An array of ConfigNodes storing the asteroid's parts. The first element MUST
        /// be the root part.</returns>
        ///
        /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot
        /// generate valid parts. 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 [] makeAsteroidParts(AsteroidSet group)
        {
            // The same "seed" that shows up in ProceduralAsteroid?
            uint   seed = (uint)UnityEngine.Random.Range(0, Int32.MaxValue);
            string part = group.drawAsteroidType();

            try {
                ConfigNode potato = ProtoVessel.CreatePartNode(part, seed);
                return(new [] { potato });
            } catch (Exception e) {
                // Really? That's what CreatePartNode throws?
                throw new InvalidOperationException(
                          Localizer.Format("#autoLOC_CustomAsteroids_ErrorTypeBadPart", part), e);
            }
        }
コード例 #7
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);
            ConfigNode trackingInfo = makeDiscoveryInfo(group);

            ConfigNode [] partList = makeAsteroidParts(group);

            // 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, new ConfigNode("ACTIONGROUPS"), trackingInfo);

            return(HighLogic.CurrentGame.AddVessel(vessel));
        }
コード例 #8
0
        /// <summary>
        /// Counts the number of asteroids from a specific set.
        /// </summary>
        /// <param name="group">The AsteroidSet of interest.</param>
        /// <returns>The number of asteroids known to have been spawned from <c>group</c>.</returns>
        internal static int countAsteroidsInSet(AsteroidSet group)
        {
            int    count = 0;
            string id    = group.getName();

            foreach (Vessel v in FlightGlobals.Vessels)
            {
                if (v.vesselType == VesselType.SpaceObject)
                {
                    AsteroidInfo info = CustomAsteroidRegistry.Instance.LookupAsteroid(v);
                    if (info != null && info.parentSet == id)
                    {
                        count++;
                    }
                }
            }
            return(count);
        }
コード例 #9
0
 /// <summary>
 /// <para>Creates a new asteroid from a randomly chosen asteroid set. The asteroid will be
 /// given the properties specified by that set, and added to the game as an untracked
 /// object.</para>
 /// <para>If asteroid creation failed for any reason, this method will log the error rather
 /// than propagating the exception into client code.</para>
 /// </summary>
 /// <returns>the newly created asteroid, or null if no asteroid was created. May be used as
 /// a hook by spawners that need more control over asteroid properties. Clients should
 /// assume the returned vessel is already registered in the game.</returns>
 /// <remarks>At least one population must have a positive spawn rate.</remarks>
 protected ProtoVessel spawnAsteroid()
 {
     try {
         AsteroidSet group    = AsteroidManager.drawAsteroidSet();
         ProtoVessel asteroid = spawnAsteroid(group);
         try {
             registerAsteroid(asteroid, group);
         } catch (ArgumentException e) {
             Debug.LogWarning("[CustomAsteroids]: Duplicate entry in CustomAsteroidRegistry.");
             Debug.LogException(e);
         }
         return(asteroid);
     } catch (Exception e) {
         Util.errorToPlayer(e, Localizer.Format("#autoLOC_CustomAsteroids_ErrorSpawnFail"));
         Debug.LogException(e);
         return(null);
     }
 }
コード例 #10
0
 /// <summary>
 ///Generates a new asteroid orbit appropriate for the chosen set.
 /// </summary>
 ///
 /// <param name="group">The set to which the asteroid belongs.</param>
 /// <returns>A randomly generated orbit.</returns>
 ///
 /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot
 /// generate valid orbits. 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 Orbit makeOrbit(AsteroidSet group)
 {
     return(group.drawOrbit());
 }
コード例 #11
0
        /// <summary>
        /// Factory method obtaining Custom Asteroids settings from KSP config state.
        /// </summary>
        ///
        /// <returns>A newly constructed PopulationLoader object containing a full list
        /// of all valid asteroid groups in asteroid config files.</returns>
        ///
        /// <exception cref="TypeInitializationException">Thrown if the PopulationLoader
        /// object could not be constructed. The program is in a consistent state in the event of
        /// an exception.</exception>
        internal static PopulationLoader load()
        {
            try {
                // Start with an empty population list
                PopulationLoader allPops = new PopulationLoader();

                // Search for populations in all config files
                UrlDir.UrlConfig [] configList = GameDatabase.Instance.GetConfigs("AsteroidSets");
                foreach (UrlDir.UrlConfig curSet in configList)
                {
                    foreach (ConfigNode curNode in curSet.config.nodes)
                    {
#if DEBUG
                        Debug.Log("[CustomAsteroids]: "
                                  + Localizer.Format("#autoLOC_CustomAsteroids_LogConfig", curNode));
#endif
                        try {
                            AsteroidSet pop = null;
                            switch (curNode.name)
                            {
                            case "ASTEROIDGROUP":
                                pop = new Population();
                                break;

                            case "INTERCEPT":
                                pop = new Flyby();
                                break;

                            case "DEFAULT":
#pragma warning disable 0618 // DefaultAsteroids is deprecated
                                pop = new DefaultAsteroids();
#pragma warning restore 0618
                                break;
                                // silently ignore any other nodes present
                            }
                            if (pop != null)
                            {
                                ConfigNode.LoadObjectFromConfig(pop, curNode);
                                allPops.asteroidPops.Add(pop);
                            }
                        } catch (Exception e) {
                            var nodeName = curNode.GetValue("name");
                            var error    = Localizer.Format(
                                "#autoLOC_CustomAsteroids_ErrorLoadGroup", nodeName);
                            Debug.LogError($"[CustomAsteroids]: " + error);
                            Debug.LogException(e);
                            Util.errorToPlayer(e, error);
                        }   // Attempt to parse remaining populations
                    }
                }

#if DEBUG
                foreach (AsteroidSet x in allPops.asteroidPops)
                {
                    Debug.Log("[CustomAsteroids]: "
                              + Localizer.Format("#autoLOC_CustomAsteroids_LogLoadGroup", x));
                }
#endif

                if (allPops.asteroidPops.Count == 0)
                {
                    Debug.LogWarning("[CustomAsteroids]: "
                                     + Localizer.Format("#autoLOC_CustomAsteroids_ErrorNoConfig1"));
                    ScreenMessages.PostScreenMessage(
                        Localizer.Format("#autoLOC_CustomAsteroids_ErrorNoConfig1") + "\n"
                        + Localizer.Format("#autoLOC_CustomAsteroids_ErrorNoConfig2"),
                        10.0f, ScreenMessageStyle.UPPER_CENTER);
                }

                return(allPops);
            } catch (Exception e) {
                throw new TypeInitializationException(
                          "Starstrider42.CustomAsteroids.PopulationLoader",
                          e);
            }
        }
コード例 #12
0
 /// <summary>
 /// Registers basic information on an asteroid in <see cref="CustomAsteroidRegistry"/>.
 /// </summary>
 /// <param name="asteroid">The asteroid to register.</param>
 /// <param name="group">The AsteroidSet from which the asteroid was drawn.</param>
 /// <remarks>This method must only be called by <see cref="spawnAsteroid()"/>, and is
 /// provided as part of the API for reference. It stores the following information:
 /// <list type="bullet">
 /// <item>
 ///     <term>parentSet</term>
 ///     <description>The unique ID of <paramref name="group"/>.</description>
 /// </item>
 /// </list>
 /// </remarks>
 static void registerAsteroid(ProtoVessel asteroid, AsteroidSet group)
 {
     CustomAsteroidRegistry.Instance.RegisterAsteroid(
         asteroid, new AsteroidInfo(asteroid, group.getName()));
 }