Example #1
0
        /// <summary>
        /// Create our SubjectData by parsing the stock "experiment@situation" subject id string.
        /// Used for asteroid samples, for compatibility with RnD archive data of removed mods and for converting stock ScienceData into SubjectData
        /// </summary>
        public static SubjectData GetSubjectDataFromStockId(string stockSubjectId, ScienceSubject RnDSubject = null)
        {
            SubjectData subjectData = null;

            if (unknownSubjectDatas.TryGetValue(stockSubjectId, out subjectData))
            {
                return(subjectData);
            }

            string[] expAndSit = stockSubjectId.Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries);

            if (expAndSit.Length != 2)
            {
                Lib.Log("Could not parse the SubjectData from subjectId '" + stockSubjectId + "' : bad format");
                return(null);
            }

            // the recovery experiment subject are created in ResearchAndDevelopment.reverseEngineerRecoveredVessel, called on the vessel recovery event
            // it use a non-standard situation system ("body" + a situation enum "RecoverySituations"). We ignore those.
            if (expAndSit[0] == "recovery")
            {
                return(null);
            }

            ExperimentInfo expInfo = GetExperimentInfo(expAndSit[0]);

            if (expInfo == null)
            {
                Lib.Log("Could not parse the SubjectData from subjectId '" + stockSubjectId + "' : the experiment id '" + expAndSit[0] + "' doesn't exists");
                return(null);
            }

            // for subject ids created with the ResearchAndDevelopment.GetExperimentSubject overload that take a "sourceUId" string,
            // the sourceUId is added to the situation after a "_"
            // in stock this seems to be used only for asteroids, and I don't think any mod use it.
            string extraSituationInfo = string.Empty;

            if (expAndSit[1].Contains("_"))
            {
                string[] sitAndAsteroid = expAndSit[1].Split('_');
                // remove
                expAndSit[1] = sitAndAsteroid[0];
                // asteroid are saved as "part.partInfo.name + part.flightID", and the part name always end with a randomly generated "AAA-000" string
                extraSituationInfo = Regex.Match(sitAndAsteroid[1], ".*?-[0-9][0-9][0-9]").Value;
                // if no match, just use the unmodified string
                if (extraSituationInfo == string.Empty)
                {
                    extraSituationInfo = sitAndAsteroid[1];
                }
            }

            string[] bodyAndBiome = expAndSit[1].Split(ScienceSituationUtils.validSituationsStrings, StringSplitOptions.RemoveEmptyEntries);
            string   situation;

            if (bodyAndBiome.Length == 1)
            {
                situation = expAndSit[1].Substring(bodyAndBiome[0].Length);
            }
            else if (bodyAndBiome.Length == 2)
            {
                situation = expAndSit[1].Substring(bodyAndBiome[0].Length, expAndSit[1].Length - bodyAndBiome[0].Length - bodyAndBiome[1].Length);
            }
            else
            {
                Lib.Log("Could not parse the SubjectData from subjectId '" + stockSubjectId + "' : the situation doesn't exists");
                return(null);
            }

            CelestialBody subjectBody = null;

            foreach (CelestialBody body in FlightGlobals.Bodies)
            {
                if (body.name == bodyAndBiome[0])
                {
                    subjectBody = body;
                    break;
                }
            }

            if (subjectBody == null)
            {
                // TODO : DMOS asteroid experiments are doing : "magScan@AsteroidInSpaceLowCarbonaceous7051371", those subjects will be discarded entirely here
                // because the body "Asteroid" doesn't exists, consequently it's impossible to create the Situation object.
                // To handle that, maybe we could implement a derived class "UnknownSituation" from Situation that can handle a completely random subject format
                Lib.Log("Could not parse the SubjectData from subjectId '" + stockSubjectId + "' : the body '" + bodyAndBiome[0] + "' doesn't exist");
                return(null);
            }

            ScienceSituation scienceSituation = ScienceSituationUtils.ScienceSituationDeserialize(situation);

            int biomeIndex = -1;

            if (bodyAndBiome.Length == 2 && ScienceSituationUtils.IsBodyBiomesRelevantForExperiment(scienceSituation, expInfo) && subjectBody.BiomeMap != null)
            {
                for (int i = 0; i < subjectBody.BiomeMap.Attributes.Length; i++)
                {
                    // Note : a stock subject has its spaces in the biome name removed but prior versions of kerbalism didn't do that,
                    // so we try to fix it, in order not to create duplicates in the RnD archives.

                    // TODO : also, we need to remove the "reentry" subjects, as stock is failing to parse them, altough this is in a try/catch block and handled gracefully.
                    string sanitizedBiome = bodyAndBiome[1].Replace(" ", string.Empty);
                    if (RnDSubject != null && extraSituationInfo == string.Empty && sanitizedBiome != bodyAndBiome[1])
                    {
                        string correctedSubjectId = expAndSit[0] + "@" + bodyAndBiome[0] + situation + sanitizedBiome;
                        RnDSubject.id = correctedSubjectId;

                        Dictionary <string, ScienceSubject> stockSubjects = Lib.ReflectionValue <Dictionary <string, ScienceSubject> >(ResearchAndDevelopment.Instance, "scienceSubjects");
                        if (stockSubjects.Remove(stockSubjectId) && !stockSubjects.ContainsKey(correctedSubjectId))
                        {
                            stockSubjects.Add(correctedSubjectId, RnDSubject);
                        }

                        Lib.Log("RnD subject load : misformatted subject '" + stockSubjectId + "' was corrected to '" + correctedSubjectId + "'");
                    }

                    if (subjectBody.BiomeMap.Attributes[i].name.Replace(" ", string.Empty).Equals(sanitizedBiome, StringComparison.OrdinalIgnoreCase))
                    {
                        biomeIndex = i;
                        break;
                    }
                }
            }

            int       bodyIndex       = subjectBody.flightGlobalsIndex;
            Situation vesselSituation = new Situation(bodyIndex, scienceSituation, biomeIndex);

            // if the subject is a "doable" subject, we should have it in the DB.
            if (extraSituationInfo == string.Empty)
            {
                subjectData = GetSubjectData(expInfo, vesselSituation);
            }

            // else create the subjectdata. this can happen either because :
            // - it's a subject using the stock "extra id" system (asteroid samples)
            // - the subject was created in RnD prior to an experiment definition config change
            // - it was created by a mod that does things in a non-stock way (ex : DMOS anomaly scans uses the anomaly name as biomes)
            if (subjectData == null)
            {
                if (bodyAndBiome.Length == 2 && bodyAndBiome[1] != string.Empty && string.IsNullOrEmpty(extraSituationInfo))
                {
                    extraSituationInfo = bodyAndBiome[1];
                }

                UnknownSubjectData unknownSubjectData = new UnknownSubjectData(expInfo, vesselSituation, stockSubjectId, RnDSubject, extraSituationInfo);
                subjectData = unknownSubjectData;
                unknownSubjectDatas.Add(stockSubjectId, unknownSubjectData);
                expBodiesSituationsBiomesSubject.AddSubject(subjectData.ExpInfo, bodyIndex, scienceSituation, biomeIndex, subjectData);
            }

            return(subjectData);
        }