Exemple #1
0
        public void Update()
        {
            if (drive == null)
            {
                return;
            }

            if (Lib.IsFlight())
            {
                // show DATA UI button, with size info
                Events["ToggleUI"].guiName = Lib.StatusToggle("Data", drive.Empty() ? "empty" : drive.Size());
                Events["ToggleUI"].active  = !IsPrivate();

                // show TakeData eva action button, if there is something to take
                Events["TakeData"].active = !drive.Empty();

                // show StoreData eva action button, if active vessel is an eva kerbal and there is something to store from it
                Vessel v = FlightGlobals.ActiveVessel;
                Events["StoreData"].active = !IsPrivate() && v != null && v.isEVA && !EVA.IsDead(v);

                // hide TransferLocation button
                var transferVisible = !IsPrivate();
                if (transferVisible)
                {
                    transferVisible = Drive.GetDrives(vessel, true).Count > 1;
                }
                Events["TransferData"].active    = transferVisible;
                Events["TransferData"].guiActive = transferVisible;
            }
        }
        static bool Prefix(DeployedScienceExperiment __instance, ref bool __result)
        {
            // get private vars
            ScienceSubject subject                = Lib.ReflectionValue <ScienceSubject>(__instance, "subject");
            float          storedScienceData      = Lib.ReflectionValue <float>(__instance, "storedScienceData");
            float          transmittedScienceData = Lib.ReflectionValue <float>(__instance, "transmittedScienceData");
            Vessel         ControllerVessel       = Lib.ReflectionValue <Vessel>(__instance, "ControllerVessel");

            //Lib.Log("SendDataToComms!: " + subject.title);
            if (__instance.Experiment != null && !(__instance.ExperimentVessel == null) && subject != null && !(__instance.Cluster == null) && __instance.sciencePart.Enabled && !(storedScienceData <= 0f) && __instance.ExperimentSituationValid)
            {
                /*	if (!__instance.TimeToSendStoredData())
                 *      {
                 *              __result = true;
                 *              Lib.Log(Lib.BuildString("BREAKING GROUND bailout 1"));
                 *              return false;
                 *      } */

                if (ControllerVessel == null && __instance.Cluster != null)
                {
                    Lib.ReflectionCall(__instance, "SetControllerVessel");
                    ControllerVessel = Lib.ReflectionValue <Vessel>(__instance, "ControllerVessel");
                }

                /*
                 * Part control;
                 * FlightGlobals.FindLoadedPart(__instance.Cluster.ControlModulePartId, out control);
                 * if(control == null) {
                 *      //Lib.Log("DeployedScienceExperiment: couldn't find control module");
                 *      __result = true;
                 *      Lib.Log(Lib.BuildString("BREAKING GROUND bailout 2"));
                 *      return false;
                 * }
                 */

                List <Drive> drives      = Drive.GetDrives(ControllerVessel, false);
                SubjectData  subjectData = ScienceDB.GetSubjectDataFromStockId(subject.id);
                foreach (Drive drive in drives)
                {
                    //Lib.Log(Lib.BuildString("BREAKING GROUND -- ", subject.id, " | ", storedScienceData.ToString()));
                    if (drive.Record_file(subjectData, storedScienceData, true))
                    {
                        //Lib.Log("BREAKING GROUND -- file recorded!");
                        Lib.ReflectionValue <float>(__instance, "transmittedScienceData", transmittedScienceData + storedScienceData);
                        Lib.ReflectionValue <float>(__instance, "storedScienceData", 0f);
                        break;
                    }
                    else
                    {
                        //Lib.Log("BREAKING GROUND -- file NOT recorded!");
                        __result = true;
                        return(false);
                    }
                }
                __result = false;
            }
            return(false);            // always return false so we don't continue to the original code
        }
Exemple #3
0
 private static Drive FindDrive(Vessel v, string filename)
 {
     foreach (var d in Drive.GetDrives(v, true))
     {
         if (d.files.ContainsKey(filename))
         {
             return(d);
         }
     }
     return(null);
 }
Exemple #4
0
 // remove a file from a vessel
 public static void RemoveFile(Vessel v, string subject_id, double amount)
 {
     if (!Cache.VesselInfo(v).is_valid)
     {
         return;
     }
     foreach (var d in Drive.GetDrives(v, true))
     {
         d.Delete_file(subject_id, amount, v.protoVessel);
     }
 }
Exemple #5
0
        // remove a sample from a vessel
        public static double RemoveSample(Vessel v, string subject_id, double amount)
        {
            if (!Cache.VesselInfo(v).is_valid)
            {
                return(0);
            }
            double massRemoved = 0;

            foreach (var d in Drive.GetDrives(v, true))
            {
                massRemoved += d.Delete_sample(subject_id, amount);
            }
            return(massRemoved);
        }
Exemple #6
0
        // return name of file being transmitted from vessel specified
        public static string Transmitting(Vessel v, bool linked)
        {
            // never transmitting if science system is disabled
            if (!Features.Science)
            {
                return(string.Empty);
            }

            // not transmitting if unlinked
            if (!linked)
            {
                return(string.Empty);
            }

            // not transmitting if there is no ec left
            if (!Lib.IsPowered(v))
            {
                return(string.Empty);
            }

            foreach (var p in Cache.WarpCache(v).files)
            {
                return(p.Key);
            }

            double now          = Planetarium.GetUniversalTime();
            double maxXmitValue = -1;
            string result       = string.Empty;

            // get first file flagged for transmission, AND has a ts at least 5 seconds old or is > 0.001Mb in size
            foreach (var drive in Drive.GetDrives(v, true))
            {
                foreach (var p in drive.files)
                {
                    if (drive.GetFileSend(p.Key) && (p.Value.ts + 3 < now || p.Value.size > min_file_size))
                    {
                        // prioritize whichever file has the most science points per byte
                        var xmitValue = Value(p.Key, p.Value.size) / p.Value.size;
                        if (string.IsNullOrEmpty(result) ||  xmitValue > maxXmitValue)
                        {
                            result       = p.Key;
                            maxXmitValue = xmitValue;
                        }
                    }
                }
            }

            return(result);
        }
Exemple #7
0
        // return size of a sample in a vessel drive
        public static double SampleSize(Vessel v, string subject_id)
        {
            if (!Cache.VesselInfo(v).is_valid)
            {
                return(0.0);
            }
            foreach (var d in Drive.GetDrives(v, true))
            {
                if (d.samples.ContainsKey(subject_id))
                {
                    return(d.samples[subject_id].size);
                }
            }

            return(0.0);
        }
Exemple #8
0
        // get next sample to analyze, return null if there isn't a sample
        private static SubjectData NextSample(Vessel v)
        {
            foreach (var drive in Drive.GetDrives(v, true))
            {
                // for each sample
                foreach (Sample sample in drive.samples.Values)
                {
                    // if flagged for analysis
                    if (sample.analyze)
                    {
                        return(sample.subjectData);
                    }
                }
            }

            // there was no sample to analyze
            return(null);
        }
Exemple #9
0
        // get next sample to analyze, return null if there isn't a sample
        private static string NextSample(Vessel v)
        {
            foreach (var drive in Drive.GetDrives(v, true))
            {
                // for each sample
                foreach (KeyValuePair <string, Sample> sample in drive.samples)
                {
                    // if flagged for analysis
                    if (sample.Value.analyze)
                    {
                        return(sample.Key);
                    }
                }
            }

            // there was no sample to analyze
            return(null);
        }
Exemple #10
0
        // return name of file being transmitted from vessel specified
        public static string Transmitting(Vessel v, bool linked)
        {
            // never transmitting if science system is disabled
            if (!Features.Science)
            {
                return(string.Empty);
            }

            // not transmitting if unlinked
            if (!linked)
            {
                return(string.Empty);
            }

            // not transmitting if there is no ec left
            if (!Lib.IsPowered(v))
            {
                return(string.Empty);
            }

            foreach (var p in Cache.WarpCache(v).files)
            {
                return(p.Key);
            }

            // get first file flagged for transmission, AND has a ts at least 5 seconds old or is > 0.001Mb in size
            foreach (var drive in Drive.GetDrives(v, true))
            {
                double now = Planetarium.GetUniversalTime();
                foreach (var p in drive.files)
                {
                    if (drive.GetFileSend(p.Key) && (p.Value.ts + 3 < now || p.Value.size > min_file_size))
                    {
                        return(p.Key);
                    }
                }
            }

            // no file flagged for transmission
            return(string.Empty);
        }
Exemple #11
0
        internal static double RecordData(ScienceData data, MetaData meta)
        {
            double remaining = data.dataAmount;

            foreach (var drive in Drive.GetDrives(meta.vessel.KerbalismData(), false))
            {
                var size = Math.Min(remaining, drive.FileCapacityAvailable());
                if (size > 0)
                {
                    drive.Record_file(meta.subjectData, size, true, true);
                    remaining -= size;
                }
            }

            if (remaining > 0)
            {
                Message.Post(
                    Lib.Color(Lib.BuildString(meta.subjectData.FullTitle, " stored partially"), Lib.Kolor.Orange),
                    "Not enough space on hard drive"
                    );
            }
            return(remaining);
        }
Exemple #12
0
        // consume EC for transmission, and transmit science data
        public static void Update(Vessel v, VesselData vd, ResourceInfo ec, double elapsed_s)
        {
            // do nothing if science system is disabled
            if (!Features.Science)
            {
                return;
            }

            // consume ec for transmitters
            ec.Consume(vd.Connection.ec_idle * elapsed_s, ResourceBroker.CommsIdle);

            // avoid corner-case when RnD isn't live during scene changes
            // - this avoid losing science if the buffer reach threshold during a scene change
            if (HighLogic.CurrentGame.Mode != Game.Modes.SANDBOX && ResearchAndDevelopment.Instance == null)
            {
                return;
            }

            // clear list of files transmitted
            vd.filesTransmitted.Clear();

            // check connection
            if (vd.Connection == null ||
                !vd.Connection.linked ||
                vd.Connection.rate <= 0.0 ||
                !vd.deviceTransmit ||
                ec.Amount < vd.Connection.ec_idle * elapsed_s)
            {
                // reset all files transmit rate
                foreach (Drive drive in Drive.GetDrives(vd, true))
                {
                    foreach (File f in drive.files.Values)
                    {
                        f.transmitRate = 0.0;
                    }
                }

                // do nothing else
                return;
            }

            double totalTransmitCapacity     = vd.Connection.rate * elapsed_s;
            double remainingTransmitCapacity = totalTransmitCapacity;

            GetFilesToTransmit(v, vd);

            if (xmitFiles.Count == 0)
            {
                return;
            }

            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.Science.Update-Loop");

            // traverse the list in reverse because :
            // - warp cache files are at the end, and they are always transmitted regerdless of transmit capacity
            // - others files are next, sorted in science value per MB ascending order
            for (int i = xmitFiles.Count - 1; i >= 0; i--)
            {
                XmitFile xmitFile = xmitFiles[i];

                if (xmitFile.file.size == 0.0)
                {
                    continue;
                }

                // always transmit everything in the warp cache
                if (!xmitFile.isInWarpCache && remainingTransmitCapacity <= 0.0)
                {
                    break;
                }

                // determine how much data is transmitted
                double transmitted = xmitFile.isInWarpCache ? xmitFile.file.size : Math.Min(xmitFile.file.size, remainingTransmitCapacity);

                if (transmitted == 0.0)
                {
                    continue;
                }

                // consume transmit capacity
                remainingTransmitCapacity -= transmitted;

                // get science value
                double xmitScienceValue = transmitted * xmitFile.sciencePerMB;

                // consume data in the file
                xmitFile.file.size -= transmitted;

                // remove science collected (ignoring final science value clamped to subject completion)
                xmitFile.file.subjectData.RemoveScienceCollectedInFlight(xmitScienceValue);

                // save transmit rate for the file, and add it to the VesselData list of files being transmitted
                if (xmitFile.isInWarpCache && xmitFile.realDriveFile != null)
                {
                    xmitFile.realDriveFile.transmitRate = transmitted / elapsed_s;
                    vd.filesTransmitted.Add(xmitFile.realDriveFile);
                }
                else
                {
                    xmitFile.file.transmitRate = transmitted / elapsed_s;
                    vd.filesTransmitted.Add(xmitFile.file);
                }

                if (xmitScienceValue > 0.0)
                {
                    // add science to the subject (and eventually included subjects), trigger completion events, credit the science, return how much has been credited.
                    vd.scienceTransmitted += xmitFile.file.subjectData.RetrieveScience(xmitScienceValue, true, v.protoVessel, xmitFile.file);
                }
            }

            UnityEngine.Profiling.Profiler.EndSample();

            // consume EC cost for transmission (ec_idle is consumed above)
            double transmittedCapacity = totalTransmitCapacity - remainingTransmitCapacity;
            double transmissionCost    = (vd.Connection.ec - vd.Connection.ec_idle) * (transmittedCapacity / (vd.Connection.rate * elapsed_s));

            ec.Consume(transmissionCost * elapsed_s, ResourceBroker.CommsXmit);
        }
Exemple #13
0
        void VesselRecoveryProcessing(ProtoVessel v, MissionRecoveryDialog dialog, float score)
        {
            // note:
            // this function accumulate science stored in drives on recovery,
            // and visualize the data in the recovery dialog window

            // do nothing if science system is disabled, or in sandbox mode
            if (!Features.Science || HighLogic.CurrentGame.Mode == Game.Modes.SANDBOX)
            {
                return;
            }

            var vesselID = Lib.VesselID(v);

            // get the drive data from DB
            if (!DB.vessels.ContainsKey(vesselID))
            {
                return;
            }

            foreach (Drive drive in Drive.GetDrives(v))
            {
                // for each file in the drive
                foreach (KeyValuePair <string, File> p in drive.files)
                {
                    // shortcuts
                    string filename = p.Key;
                    File   file     = p.Value;

                    // de-buffer partially transmitted data
                    file.size += file.buff;
                    file.buff  = 0.0;

                    // get subject
                    ScienceSubject subject = ResearchAndDevelopment.GetSubjectByID(filename);

                    // credit science
                    float credits = Science.Credit(filename, file.size, false, v);

                    // create science widged
                    ScienceSubjectWidget widged = ScienceSubjectWidget.Create
                                                  (
                        subject,                              // subject
                        (float)file.size,                     // data gathered
                        credits,                              // science points
                        dialog                                // recovery dialog
                                                  );

                    // add widget to dialog
                    dialog.AddDataWidget(widged);

                    // add science credits to total
                    dialog.scienceEarned += (float)credits;
                }

                // for each sample in the drive
                // for each file in the drive
                foreach (KeyValuePair <string, Sample> p in drive.samples)
                {
                    // shortcuts
                    string filename = p.Key;
                    Sample sample   = p.Value;

                    // get subject
                    ScienceSubject subject = ResearchAndDevelopment.GetSubjectByID(filename);

                    // credit science
                    float credits = Science.Credit(filename, sample.size, false, v);

                    // create science widged
                    ScienceSubjectWidget widged = ScienceSubjectWidget.Create
                                                  (
                        subject,                              // subject
                        (float)sample.size,                   // data gathered
                        credits,                              // science points
                        dialog                                // recovery dialog
                                                  );

                    // add widget to dialog
                    dialog.AddDataWidget(widged);

                    // add science credits to total
                    dialog.scienceEarned += (float)credits;
                }
            }
        }
Exemple #14
0
        public static void BackgroundUpdate(Vessel vessel, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, KerbalismScansat kerbalismScansat,
                                            Part part_prefab, VesselData vd, Resource_info ec, double elapsed_s)
        {
            List <ProtoPartModuleSnapshot> scanners = Cache.VesselObjectsCache <List <ProtoPartModuleSnapshot> >(vessel, "scansat_" + p.flightID);

            if (scanners == null)
            {
                scanners = Lib.FindModules(p, "SCANsat");
                if (scanners.Count == 0)
                {
                    scanners = Lib.FindModules(p, "ModuleSCANresourceScanner");
                }
                Cache.SetVesselObjectsCache(vessel, "scansat_" + p.flightID, scanners);
            }

            if (scanners.Count == 0)
            {
                return;
            }
            var scanner = scanners[0];

            bool is_scanning = Lib.Proto.GetBool(scanner, "scanning");

            if (is_scanning && kerbalismScansat.ec_rate > double.Epsilon)
            {
                ec.Consume(kerbalismScansat.ec_rate * elapsed_s, "scanner");
            }

            if (!Features.Science)
            {
                if (is_scanning && ec.amount < double.Epsilon)
                {
                    SCANsat.StopScanner(vessel, scanner, part_prefab);
                    is_scanning = false;

                    // remember disabled scanner
                    vd.scansat_id.Add(p.flightID);

                    // give the user some feedback
                    if (vd.cfg_ec)
                    {
                        Message.Post(Lib.BuildString("SCANsat sensor was disabled on <b>", vessel.vesselName, "</b>"));
                    }
                }
                else if (vd.scansat_id.Contains(p.flightID))
                {
                    // if there is enough ec
                    // note: comparing against amount in previous simulation step
                    // re-enable at 25% EC
                    if (ec.level > 0.25)
                    {
                        // re-enable the scanner
                        SCANsat.ResumeScanner(vessel, m, part_prefab);
                        is_scanning = true;

                        // give the user some feedback
                        if (vd.cfg_ec)
                        {
                            Message.Post(Lib.BuildString("SCANsat sensor resumed operations on <b>", vessel.vesselName, "</b>"));
                        }
                    }
                }

                // forget active scanners
                if (is_scanning)
                {
                    vd.scansat_id.Remove(p.flightID);
                }

                return;
            }             // if(!Feature.Science)

            string body_name     = Lib.Proto.GetString(m, "body_name");
            int    sensorType    = (int)Lib.Proto.GetUInt(m, "sensorType");
            double body_coverage = Lib.Proto.GetDouble(m, "body_coverage");
            double warp_buffer   = Lib.Proto.GetDouble(m, "warp_buffer");

            double new_coverage = SCANsat.Coverage(sensorType, vessel.mainBody);

            if (body_name == vessel.mainBody.name && new_coverage < body_coverage)
            {
                // SCANsat sometimes reports a coverage of 0, which is wrong
                new_coverage = body_coverage;
            }

            if (vessel.mainBody.name != body_name)
            {
                body_name     = vessel.mainBody.name;
                body_coverage = new_coverage;
            }
            else
            {
                double coverage_delta = new_coverage - body_coverage;
                body_coverage = new_coverage;

                if (is_scanning)
                {
                    Science.Generate_subject(kerbalismScansat.experimentType, vessel);
                    var    subject_id = Science.Generate_subject_id(kerbalismScansat.experimentType, vessel);
                    var    exp        = Science.Experiment(subject_id);
                    double size       = exp.max_amount * coverage_delta / 100.0;               // coverage is 0-100%
                    size += warp_buffer;

                    if (size > double.Epsilon)
                    {
                        // store what we can
                        foreach (var d in Drive.GetDrives(vessel))
                        {
                            var available = d.FileCapacityAvailable();
                            var chunk     = Math.Min(size, available);
                            if (!d.Record_file(subject_id, chunk, true))
                            {
                                break;
                            }
                            size -= chunk;

                            if (size < double.Epsilon)
                            {
                                break;
                            }
                        }
                    }

                    if (size > double.Epsilon)
                    {
                        // we filled all drives up to the brim but were unable to store everything
                        if (warp_buffer < double.Epsilon)
                        {
                            // warp buffer is empty, so lets store the rest there
                            warp_buffer = size;
                            size        = 0;
                        }
                        else
                        {
                            // warp buffer not empty. that's ok if we didn't get new data
                            if (coverage_delta < double.Epsilon)
                            {
                                size = 0;
                            }
                            // else we're scanning too fast. stop.
                        }
                    }

                    // we filled all drives up to the brim but were unable to store everything
                    // cancel scanning and annoy the user
                    if (size > double.Epsilon || ec.amount < double.Epsilon)
                    {
                        warp_buffer = 0;
                        SCANsat.StopScanner(vessel, scanner, part_prefab);
                        vd.scansat_id.Add(p.flightID);
                        if (vd.cfg_ec)
                        {
                            Message.Post(Lib.BuildString("SCANsat sensor was disabled on <b>", vessel.vesselName, "</b>"));
                        }
                    }
                }
                else if (vd.scansat_id.Contains(p.flightID))
                {
                    var vi = Cache.VesselInfo(vessel);
                    if (ec.level >= 0.25 && (vi.free_capacity / vi.total_capacity > 0.9))
                    {
                        SCANsat.ResumeScanner(vessel, scanner, part_prefab);
                        vd.scansat_id.Remove(p.flightID);
                        if (vd.cfg_ec)
                        {
                            Message.Post(Lib.BuildString("SCANsat sensor resumed operations on <b>", vessel.vesselName, "</b>"));
                        }
                    }
                }
            }

            Lib.Proto.Set(m, "warp_buffer", warp_buffer);
            Lib.Proto.Set(m, "body_coverage", body_coverage);
            Lib.Proto.Set(m, "body_name", body_name);
        }
Exemple #15
0
        private static void GetFilesToTransmit(Vessel v, VesselData vd)
        {
            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.Science.GetFilesToTransmit");
            Drive warpCache = Cache.WarpCache(v);

            xmitFiles.Clear();
            List <SubjectData> filesToRemove = new List <SubjectData>();

            foreach (Drive drive in Drive.GetDrives(vd, true))
            {
                foreach (File f in drive.files.Values)
                {
                    // always reset transmit rate
                    f.transmitRate = 0.0;

                    // delete empty files that aren't being transmitted
                    // note : this won't work in case the same subject is split over multiple files (on different drives)
                    if (f.size <= 0.0 && (!warpCache.files.ContainsKey(f.subjectData) || warpCache.files[f.subjectData].size <= 0.0))
                    {
                        filesToRemove.Add(f.subjectData);
                        continue;
                    }

                    // get files tagged for transmit
                    if (drive.GetFileSend(f.subjectData.Id))
                    {
                        xmitFiles.Add(new XmitFile(f, drive, f.subjectData.SciencePerMB, false));
                    }
                }

                // delete found empty files from the drive
                foreach (SubjectData fileToRemove in filesToRemove)
                {
                    drive.files.Remove(fileToRemove);
                }

                filesToRemove.Clear();
            }

            // sort files by science value per MB ascending order so high value files are transmitted first
            // because XmitFile list is processed from end to start
            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.Science.GetFilesToTransmit-Sort");
            xmitFiles.Sort((x, y) => x.sciencePerMB.CompareTo(y.sciencePerMB));
            UnityEngine.Profiling.Profiler.EndSample();

            // add all warpcache files to the beginning of the XmitFile list
            foreach (File f in warpCache.files.Values)
            {
                // don't transmit empty files
                if (f.size <= 0.0)
                {
                    continue;
                }

                // find the file on a "real" drive that correspond to this warpcache file
                // this allow to use the real file for displaying transmit info and saving state (filemanager, monitor, vesseldata...)
                int driveFileIndex = xmitFiles.FindIndex(df => df.file.subjectData == f.subjectData);
                if (driveFileIndex >= 0)
                {
                    xmitFiles.Add(new XmitFile(f, warpCache, f.subjectData.SciencePerMB, true, xmitFiles[driveFileIndex].file));
                }
                else
                {
                    xmitFiles.Add(new XmitFile(f, warpCache, f.subjectData.SciencePerMB, true));                     // should not be happening, but better safe than sorry
                }
            }
            UnityEngine.Profiling.Profiler.EndSample();
        }
Exemple #16
0
        public void Update()
        {
            if (drive == null)
            {
                return;
            }

            if (Lib.IsEditor())
            {
                bool update = false;
                if (dataCapacities != null)
                {
                    foreach (var c in dataCapacities)
                    {
                        if (c.Key == dataCapacityUI)
                        {
                            update |= effectiveDataCapacity != c.Value;
                            effectiveDataCapacity = c.Value;
                        }
                    }
                }

                if (sampleCapacities != null)
                {
                    foreach (var c in sampleCapacities)
                    {
                        if (c.Key == sampleCapacityUI)
                        {
                            update |= effectiveSampleCapacity != c.Value;
                            effectiveSampleCapacity = c.Value;
                        }
                    }
                }

                drive.dataCapacity   = effectiveDataCapacity;
                drive.sampleCapacity = effectiveSampleCapacity;

                Fields["sampleCapacityUI"].guiActiveEditor = sampleCapacity > 0;
                Fields["dataCapacityUI"].guiActiveEditor   = dataCapacity > 0;

                if (update)
                {
                    GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship);
                    UpdateCapacity();
                }
            }

            if (Lib.IsFlight())
            {
                // show DATA UI button, with size info
                Events["ToggleUI"].guiName = Lib.StatusToggle("Data", drive.Empty() ? "empty" : drive.Size());
                Events["ToggleUI"].active  = !IsPrivate();

                // show TakeData eva action button, if there is something to take
                Events["TakeData"].active = !drive.Empty();

                // show StoreData eva action button, if active vessel is an eva kerbal and there is something to store from it
                Vessel v = FlightGlobals.ActiveVessel;
                Events["StoreData"].active = !IsPrivate() && v != null && v.isEVA && !EVA.IsDead(v);

                // hide TransferLocation button
                var transferVisible = !IsPrivate();
                if (transferVisible)
                {
                    transferVisible = Drive.GetDrives(vessel, true).Count > 1;
                }
                Events["TransferData"].active    = transferVisible;
                Events["TransferData"].guiActive = transferVisible;
            }
        }
Exemple #17
0
        // analyze a sample
        private static Status Analyze(Vessel v, SubjectData subject, double amount)
        {
            Sample sample      = null;
            Drive  sampleDrive = null;

            foreach (var d in Drive.GetDrives(v, true))
            {
                if (d.samples.ContainsKey(subject) && d.samples[subject].analyze)
                {
                    sample      = d.samples[subject];
                    sampleDrive = d;
                    break;
                }
            }

            bool completed = false;

            if (sample != null)
            {
                completed = amount > sample.size;
                amount    = Math.Min(amount, sample.size);
            }

            Drive fileDrive = Drive.FileDrive(v.KerbalismData(), amount);

            if (fileDrive == null)
            {
                return(Status.NO_STORAGE);
            }

            if (sample != null)
            {
                bool recorded = fileDrive.Record_file(subject, amount, false);

                double massRemoved = 0.0;
                if (recorded)
                {
                    massRemoved = sampleDrive.Delete_sample(subject, amount);
                }
                else
                {
                    Message.Post(
                        Lib.Color(Lib.BuildString(Localizer.Format("#KERBALISM_Laboratory_Analysis"), " stopped"), Lib.Kolor.Red),
                        "Not enough space on hard drive"
                        );

                    return(Status.NO_STORAGE);
                }

                // return sample mass to experiment if needed
                if (massRemoved > 0.0)
                {
                    RestoreSampleMass(v, subject, massRemoved);
                }
            }

            // if the analysis is completed
            if (completed)
            {
                if (!PreferencesScience.Instance.analyzeSamples)
                {
                    // only inform the user if auto-analyze is turned off
                    // otherwise we could be spamming "Analysis complete" messages
                    Message.Post(Lib.BuildString(Lib.Color(Localizer.Format("#KERBALISM_Laboratory_Analysis"), Lib.Kolor.Science, true), "\n",
                                                 Localizer.Format("#KERBALISM_Laboratory_Analyzed", Lib.Bold(v.vesselName), Lib.Bold(subject.FullTitle))), localized_results);
                }

                if (PreferencesScience.Instance.transmitScience)
                {
                    fileDrive.Send(subject.Id, true);
                }

                // record landmark event
                if (!Lib.Landed(v))
                {
                    DB.landmarks.space_analysis = true;
                }
            }

            return(Status.RUNNING);
        }
Exemple #18
0
        void Record(MetaData meta, ScienceData data, bool send)
        {
            // if amount is zero, warn the user and do nothing else
            if (data.dataAmount <= double.Epsilon)
            {
                Message.Post("There is no more useful data here");
                return;
            }

            // if this is a sample and we are trying to send it, warn the user and do nothing else
            if (meta.is_sample && send)
            {
                Message.Post("We can't transmit a sample", "It needs to be recovered, or analyzed in a lab");
                return;
            }

            // record data in the drive
            bool recorded = false;

            if (!meta.is_sample)
            {
                Drive drive = Drive.FileDrive(meta.vessel, data.dataAmount);
                recorded = drive.Record_file(data.subjectID, data.dataAmount);
            }
            else
            {
                Drive drive = Drive.SampleDrive(meta.vessel, data.dataAmount, data.subjectID);

                var experimentInfo = Science.Experiment(data.subjectID);
                var sampleMass     = Science.GetSampleMass(data.subjectID);
                var mass           = sampleMass / experimentInfo.max_amount * data.dataAmount;

                recorded = drive.Record_sample(data.subjectID, data.dataAmount, mass);
            }

            if (recorded)
            {
                // flag for sending if specified
                if (!meta.is_sample && send)
                {
                    foreach (var d in Drive.GetDrives(meta.vessel))
                    {
                        d.Send(data.subjectID, true);
                    }
                }

                // render experiment inoperable if necessary
                if (!meta.is_rerunnable)
                {
                    meta.experiment.SetInoperable();
                }

                // dismiss the dialog and popups
                Dismiss(data);

                var exp = Science.Experiment(data.subjectID);
                // inform the user
                Message.Post(
                    Lib.BuildString("<b>", exp.FullName(data.subjectID), "</b> recorded"),
                    !meta.is_rerunnable ? Localizer.Format("#KERBALISM_Science_inoperable") : string.Empty
                    );
            }
            else
            {
                var exp = Science.Experiment(data.subjectID);
                Message.Post(
                    Lib.Color("red", Lib.BuildString(exp.FullName(data.subjectID), " can not be stored")),
                    "Not enough space on hard drive"
                    );
            }
        }
Exemple #19
0
        public void FixedUpdate()
        {
            if (scanner == null)
            {
                return;
            }
            if (!Features.Science)
            {
                return;
            }

            IsScanning = SCANsat.IsScanning(scanner);
            double new_coverage = SCANsat.Coverage(sensorType, vessel.mainBody);

            if (body_name == vessel.mainBody.name && new_coverage < body_coverage)
            {
                // SCANsat sometimes reports a coverage of 0, which is wrong
                new_coverage = body_coverage;
            }

            if (vessel.mainBody.name != body_name)
            {
                body_name     = vessel.mainBody.name;
                body_coverage = new_coverage;
            }
            else
            {
                double coverage_delta = new_coverage - body_coverage;
                body_coverage = new_coverage;
                var vd = DB.Vessel(vessel);

                if (IsScanning)
                {
                    Science.Generate_subject(experimentType, vessel);
                    var    subject_id = Science.Generate_subject_id(experimentType, vessel);
                    var    exp        = Science.Experiment(subject_id);
                    double size       = exp.max_amount * coverage_delta / 100.0;               // coverage is 0-100%

                    size += warp_buffer;

                    if (size > double.Epsilon)
                    {
                        // store what we can
                        foreach (var d in Drive.GetDrives(vessel))
                        {
                            var available = d.FileCapacityAvailable();
                            var chunk     = Math.Min(size, available);
                            if (!d.Record_file(subject_id, chunk, true))
                            {
                                break;
                            }
                            size -= chunk;

                            if (size < double.Epsilon)
                            {
                                break;
                            }
                        }
                    }

                    if (size > double.Epsilon)
                    {
                        // we filled all drives up to the brim but were unable to store everything
                        if (warp_buffer < double.Epsilon)
                        {
                            // warp buffer is empty, so lets store the rest there
                            warp_buffer = size;
                            size        = 0;
                        }
                        else
                        {
                            // warp buffer not empty. that's ok if we didn't get new data
                            if (coverage_delta < double.Epsilon)
                            {
                                size = 0;
                            }
                            // else we're scanning too fast. stop.
                        }

                        // cancel scanning and annoy the user
                        if (size > double.Epsilon)
                        {
                            warp_buffer = 0;
                            StopScan();
                            vd.scansat_id.Add(part.flightID);
                            Message.Post(Lib.Color("red", "Scanner halted", true), "Scanner halted on <b>" + vessel.vesselName + "</b>. No storage left on vessel.");
                        }
                    }
                }
                else if (vd.scansat_id.Contains(part.flightID))
                {
                    var vi = Cache.VesselInfo(vessel);
                    if (vi.free_capacity / vi.total_capacity > 0.9)                    // restart when 90% of capacity is available
                    {
                        StartScan();
                        vd.scansat_id.Remove(part.flightID);
                        if (vd.cfg_ec)
                        {
                            Message.Post(Lib.BuildString("SCANsat sensor resumed operations on <b>", vessel.vesselName, "</b>"));
                        }
                    }
                }
            }
        }
        static bool Prefix(ref ProtoVessel pv, ref bool quick)
        {
            if (pv == null)
            {
                return(true);
            }

            // get a hard drive. any hard drive will do, no need to find a specific one.
            ProtoPartModuleSnapshot protoHardDrive = null;

            foreach (var p in pv.protoPartSnapshots)
            {
                foreach (var pm in Lib.FindModules(p, "HardDrive"))
                {
                    protoHardDrive = pm;
                    break;
                }
                if (protoHardDrive != null)
                {
                    break;
                }
            }

            if (protoHardDrive == null)
            {
                return(true);                // no drive on the vessel - nothing to do.
            }
            double scienceToCredit = 0.0;

            List <DialogGUIBase> labels = new List <DialogGUIBase>();

            foreach (Drive drive in Drive.GetDrives(pv, true))
            {
                foreach (File file in drive.files.Values)
                {
                    double subjectValue = file.subjectData.ScienceValue(file.size);
                    file.subjectData.RemoveScienceCollectedInFlight(subjectValue);

                    if (file.useStockCrediting)
                    {
                        file.ConvertToStockData().Save(protoHardDrive.moduleValues.AddNode("ScienceData"));

                        if (!file.subjectData.ExistsInRnD)
                        {
                            file.subjectData.CreateSubjectInRnD();
                        }

                        file.subjectData.SetAsPersistent();
                        file.subjectData.UpdateSubjectCompletion(subjectValue);
                    }
                    else
                    {
                        scienceToCredit += file.subjectData.RetrieveScience(subjectValue, false, pv);

                        labels.Add(new DialogGUILabel(Lib.BuildString(
                                                          Lib.Color("+ " + subjectValue.ToString("F1"), Lib.Kolor.Science),
                                                          " (",
                                                          Lib.Color(file.subjectData.ScienceRetrievedInKSC.ToString("F1"), Lib.Kolor.Science, true),
                                                          " / ",
                                                          Lib.Color(file.subjectData.ScienceMaxValue.ToString("F1"), Lib.Kolor.Science, true),
                                                          ") : ",
                                                          file.subjectData.FullTitle
                                                          )));
                    }
                }

                foreach (Sample sample in drive.samples.Values)
                {
                    double subjectValue = sample.subjectData.ScienceValue(sample.size);
                    sample.subjectData.RemoveScienceCollectedInFlight(subjectValue);

                    if (sample.useStockCrediting)
                    {
                        sample.ConvertToStockData().Save(protoHardDrive.moduleValues.AddNode("ScienceData"));

                        if (!sample.subjectData.ExistsInRnD)
                        {
                            sample.subjectData.CreateSubjectInRnD();
                        }

                        sample.subjectData.SetAsPersistent();
                        sample.subjectData.UpdateSubjectCompletion(subjectValue);
                    }
                    else
                    {
                        scienceToCredit += sample.subjectData.RetrieveScience(subjectValue, false, pv);

                        labels.Add(new DialogGUILabel(Lib.BuildString(
                                                          Lib.Color("+ " + subjectValue.ToString("F1"), Lib.Kolor.Science),
                                                          " (",
                                                          Lib.Color(sample.subjectData.ScienceRetrievedInKSC.ToString("F1"), Lib.Kolor.Science, true),
                                                          " / ",
                                                          Lib.Color(sample.subjectData.ScienceMaxValue.ToString("F1"), Lib.Kolor.Science, true),
                                                          ") : ",
                                                          sample.subjectData.FullTitle
                                                          )));
                    }
                }
            }

            protoHardDrive.moduleName = "ModuleScienceContainer";

            if (scienceToCredit > 0.0)
            {
                // ideally we should hack the stock dialog to add the little science widgets to it but I'm lazy
                // plus it looks like crap anyway
                PopupDialog.SpawnPopupDialog
                (
                    new MultiOptionDialog
                    (
                        "scienceResults", "", pv.vesselName + " " + Local.VesselRecovery_title, HighLogic.UISkin, new Rect(0.3f, 0.5f, 350f, 100f),                      //" recovery"
                        new DialogGUIVerticalLayout
                        (
                            new DialogGUIBox(Local.VesselRecovery_info + " : " + Lib.Color(scienceToCredit.ToString("F1") + " " + Local.VesselRecovery_CREDITS, Lib.Kolor.Science, true), 340f, 30f),                            //"SCIENCE RECOVERED"" CREDITS"
                            new DialogGUIScrollList
                            (
                                new Vector2(340f, 250f), false, true,
                                new DialogGUIVerticalLayout(labels.ToArray())
                            ),
                            new DialogGUIButton(Local.VesselRecovery_OKbutton, null, 340f, 30f, true, HighLogic.UISkin.button)                            //"OK"
                        )
                    ),
                    false, HighLogic.UISkin
                );
            }

            return(true);            // continue to the original code
        }
Exemple #21
0
        // consume EC for transmission, and transmit science data
        public static void Update(Vessel v, VesselData vd, ResourceInfo ec, double elapsed_s)
        {
            // do nothing if science system is disabled
            if (!Features.Science)
            {
                return;
            }

            // consume ec for transmitters
            ec.Consume(vd.Connection.ec_idle * elapsed_s, ResourceBroker.CommsIdle);

            // avoid corner-case when RnD isn't live during scene changes
            // - this avoid losing science if the buffer reach threshold during a scene change
            if (HighLogic.CurrentGame.Mode != Game.Modes.SANDBOX && ResearchAndDevelopment.Instance == null)
            {
                return;
            }

            // clear list of files transmitted
            vd.filesTransmitted.Clear();

            // check connection
            if (vd.Connection == null ||
                !vd.Connection.linked ||
                vd.Connection.rate <= 0.0 ||
                !vd.deviceTransmit ||
                ec.Amount < vd.Connection.ec_idle * elapsed_s)
            {
                // reset all files transmit rate
                foreach (Drive drive in Drive.GetDrives(vd, true))
                {
                    foreach (File f in drive.files.Values)
                    {
                        f.transmitRate = 0.0;
                    }
                }

                // do nothing else
                return;
            }

            double totalTransmitCapacity     = vd.Connection.rate * elapsed_s;
            double remainingTransmitCapacity = totalTransmitCapacity;
            double scienceCredited           = 0.0;

            GetFilesToTransmit(v, vd);

            if (xmitFiles.Count == 0)
            {
                return;
            }

            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.Science.Update-Loop");

            // traverse the list in reverse because :
            // - warp cache files are at the end, and they are always transmitted regerdless of transmit capacity
            // - others files are next, sorted in science value per MB ascending order
            for (int i = xmitFiles.Count - 1; i >= 0; i--)
            {
                XmitFile xmitFile = xmitFiles[i];

                if (xmitFile.file.size == 0.0)
                {
                    continue;
                }

                // always transmit everything in the warp cache
                if (!xmitFile.isInWarpCache && remainingTransmitCapacity <= 0.0)
                {
                    break;
                }

                // determine how much data is transmitted
                double transmitted = xmitFile.isInWarpCache ? xmitFile.file.size : Math.Min(xmitFile.file.size, remainingTransmitCapacity);

                if (transmitted == 0.0)
                {
                    continue;
                }

                // consume transmit capacity
                remainingTransmitCapacity -= transmitted;

                // get science value
                double xmitScienceValue = transmitted * xmitFile.sciencePerMB;

                // consume data in the file
                xmitFile.file.size -= transmitted;

                // remove science collected (ignoring final science value clamped to subject completion)
                xmitFile.file.subjectData.RemoveScienceCollectedInFlight(xmitScienceValue);

                // fire subject completed events
                int timesCompleted = xmitFile.file.subjectData.UpdateSubjectCompletion(xmitScienceValue);
                if (timesCompleted > 0)
                {
                    SubjectXmitCompleted(xmitFile.file, timesCompleted, v);
                }

                // save transmit rate for the file, and add it to the VesselData list of files being transmitted
                if (xmitFile.isInWarpCache && xmitFile.realDriveFile != null)
                {
                    xmitFile.realDriveFile.transmitRate = transmitted / elapsed_s;
                    vd.filesTransmitted.Add(xmitFile.realDriveFile);
                }
                else
                {
                    xmitFile.file.transmitRate = transmitted / elapsed_s;
                    vd.filesTransmitted.Add(xmitFile.file);
                }

                // clamp science value to subject max value
                xmitScienceValue = Math.Min(xmitScienceValue, xmitFile.file.subjectData.ScienceRemainingToRetrieve);

                if (xmitScienceValue > 0.0)
                {
                    // add credits
                    scienceCredited += xmitScienceValue;

                    // credit the subject
                    xmitFile.file.subjectData.AddScienceToRnDSubject(xmitScienceValue);
                }
            }

            UnityEngine.Profiling.Profiler.EndSample();

            vd.scienceTransmitted += scienceCredited;

            // consume EC cost for transmission (ec_idle is consumed above)
            double transmittedCapacity = totalTransmitCapacity - remainingTransmitCapacity;
            double transmissionCost    = (vd.Connection.ec - vd.Connection.ec_idle) * (transmittedCapacity / vd.Connection.rate);

            ec.Consume(transmissionCost, ResourceBroker.CommsXmit);

            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.Science.Update-AddScience");

            // Add science points, but wait until we have at least 0.1 points to add because AddScience is VERY slow
            // We don't use "TransactionReasons.ScienceTransmission" because AddScience fire multiple events not meant to be fired continuously
            // this avoid many side issues (ex : chatterer transmit sound playing continously, strategia "+0.0 science" popup...)
            ScienceDB.uncreditedScience += scienceCredited;
            if (ScienceDB.uncreditedScience > 0.1)
            {
                if (GameHasRnD)
                {
                    ResearchAndDevelopment.Instance.AddScience((float)ScienceDB.uncreditedScience, TransactionReasons.None);
                }

                ScienceDB.uncreditedScience = 0.0;
            }

            UnityEngine.Profiling.Profiler.EndSample();
        }
Exemple #22
0
        void Record(MetaData meta, ScienceData data, bool send)
        {
            // if amount is zero, warn the user and do nothing else
            if (data.dataAmount <= double.Epsilon)
            {
                Message.Post("There is no more useful data here");
                return;
            }

            if (meta.subjectData == null)
            {
                return;
            }

            // if this is a sample and we are trying to send it, warn the user and do nothing else
            if (meta.is_sample && send)
            {
                Message.Post("We can't transmit a sample", "It needs to be recovered, or analyzed in a lab");
                return;
            }

            // record data in the drive
            bool recorded       = false;
            bool partial_record = false;

            if (!meta.is_sample)
            {
                var remaining = MiniHijacker.RecordData(data, meta);
                if (remaining > 0)
                {
                    partial_record = true;
                }
                recorded = remaining < data.dataAmount;
            }
            else
            {
                Drive drive = Drive.SampleDrive(meta.vessel.KerbalismData(), data.dataAmount, meta.subjectData);
                if (drive != null)
                {
                    recorded = drive.Record_sample(meta.subjectData, data.dataAmount, meta.subjectData.ExpInfo.MassPerMB * data.dataAmount, true);
                }
            }

            if (recorded)
            {
                // flag for sending if specified
                if (!meta.is_sample && send)
                {
                    foreach (var d in Drive.GetDrives(meta.vessel))
                    {
                        d.Send(data.subjectID, true);
                    }
                }

                // render experiment inoperable if necessary
                if (!meta.is_rerunnable && !partial_record)
                {
                    meta.experiment.SetInoperable();
                }

                // dismiss the dialog and popups
                Dismiss(data);

                if (!partial_record)
                {
                    // inform the user
                    Message.Post(
                        Lib.BuildString("<b>", meta.subjectData.FullTitle, "</b> recorded"),
                        !meta.is_rerunnable ? Local.Science_inoperable : string.Empty
                        );
                }
            }
            else
            {
                Message.Post(
                    Lib.Color(Lib.BuildString(meta.subjectData.FullTitle, " can not be stored"), Lib.Kolor.Red),
                    "Not enough space on hard drive"
                    );
            }
        }