public override void OnLoad(ConfigNode node) { // deserialize data DB.load(node); // initialize everything just once if (!initialized) { // add supply resources to pods Profile.SetupPods(); // initialize subsystems Cache.init(); ResourceCache.init(); Radiation.init(); Science.init(); LineRenderer.init(); ParticleRenderer.init(); Highlighter.init(); UI.init(); // prepare storm data foreach (CelestialBody body in FlightGlobals.Bodies) { if (Storm.skip_body(body)) { continue; } storm_data sd = new storm_data(); sd.body = body; storm_bodies.Add(sd); } // various tweaks to the part icons in the editor Misc.TweakPartIcons(); // setup callbacks callbacks = new Callbacks(); // everything was initialized initialized = true; } // detect if this is a different savegame if (DB.uid != savegame_uid) { // clear caches Cache.clear(); ResourceCache.clear(); // sync main window pos from db UI.sync(); // remember savegame id savegame_uid = DB.uid; } // force CommNet off when signal is enabled HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet &= !Features.Signal; }
void Start() { // create subsystems cache = new Cache(); resource_cache = new ResourceCache(); background = new Background(); signal = new Signal(); storm = new Storm(); launcher = new Launcher(); info = new Info(); body_info = new BodyInfo(); message = new Message(); console = new Console(); editor = new Editor(); Radiation.init(); LineRenderer.init(); ParticleRenderer.init(); // prepare storm data foreach(CelestialBody body in FlightGlobals.Bodies) { if (Storm.skip_body(body)) continue; storm_data sd = new storm_data(); sd.body = body; storm_bodies.Add(sd); } }
public override void OnLoad(ConfigNode node) { // deserialize data DB.Load(node); // initialize everything just once if (!initialized) { // add supply resources to pods Profile.SetupPods(); // initialize subsystems Cache.Init(); ResourceCache.Init(); Radiation.Init(); Science.Init(); LineRenderer.Init(); ParticleRenderer.Init(); Highlighter.Init(); UI.Init(); // prepare storm data foreach (CelestialBody body in FlightGlobals.Bodies) { if (Storm.Skip_body(body)) { continue; } Storm_data sd = new Storm_data { body = body }; storm_bodies.Add(sd); } // various tweaks to the part icons in the editor Misc.TweakPartIcons(); // setup callbacks callbacks = new Callbacks(); // everything was initialized initialized = true; } // detect if this is a different savegame if (DB.uid != savegame_uid) { // clear caches Cache.Clear(); ResourceCache.Clear(); // sync main window pos from db UI.Sync(); // remember savegame id savegame_uid = DB.uid; } }
// return true if a solar storm is in progress at the vessel position public static bool StormInProgress(Vessel v) { if (!Features.SpaceWeather) { return(false); } return(Cache.VesselInfo(v).is_valid&& Storm.InProgress(v)); }
// --- SPACE WEATHER -------------------------------------------------------- // return true if a solar storm is incoming at the vessel position public static bool StormIncoming(Vessel v) { if (!Features.SpaceWeather) { return(false); } return(v.KerbalismData().IsSimulated&& Storm.Incoming(v)); }
public void update(Vessel v, vessel_info vi, vessel_data vd, vessel_resources resources, double elapsed_s) { // do nothing if signal mechanic is disabled if (!Kerbalism.features.signal) { return; } // get link data link_data link = vi.link; // consume relay ec // note: this is the only way to do it with new signal and resource systems if (vi.antenna.relay_range > 0.0) { foreach (Vessel w in FlightGlobals.Vessels) { vessel_info wi = Cache.VesselInfo(w); if (wi.is_valid) { if (wi.link.path.Contains(v)) { resources.Consume(v, "ElectricCharge", vi.antenna.relay_cost * elapsed_s); break; } } } } // maintain and send messages // - do nothing if db isn't ready // - do not send messages for vessels without an antenna if (link.status != link_status.no_antenna) { if (vd.msg_signal < 1 && !link.linked) { vd.msg_signal = 1; if (vd.cfg_signal == 1 && !vi.blackout) //< do not send message during storms { Message.Post(Severity.warning, Lib.BuildString("Signal lost with <b>", v.vesselName, "</b>"), vi.crew_count == 0 && Settings.RemoteControlLink ? "Remote control disabled" : "Data transmission disabled"); } } else if (vd.msg_signal > 0 && link.linked) { vd.msg_signal = 0; if (vd.cfg_signal == 1 && !Storm.JustEnded(v, elapsed_s)) //< do not send messages after a storm { var path = link.path; Message.Post(Severity.relax, Lib.BuildString("<b>", v.vesselName, "</b> signal is back"), path.Count == 0 ? "We got a direct link with the space center" : Lib.BuildString("Relayed by <b>", path[path.Count - 1].vesselName, "</b>")); } } } }
public void BuildLinks() { // clear links container links.Clear(); // clear active relays container active_relays.Clear(); // iterate over all vessels foreach (Vessel v in FlightGlobals.Vessels) { // skip invalid vessels if (!Lib.IsVessel(v)) { continue; } // generate and store link status link_data ld = ComputeLink(v, new HashSet <Guid>()); links.Add(v.id, ld); // maintain and send messages // - do nothing if db isn't ready // - do not send messages for vessels without an antenna if (DB.Ready() && ld.status != link_status.no_antenna) { vessel_data vd = DB.VesselData(v.id); if (vd.msg_signal < 1 && !ld.linked) { vd.msg_signal = 1; if (DB.Ready()) { DB.NotificationData().first_signal_loss = 1; //< record first signal loss } if (vd.cfg_signal == 1 && !Blackout(v)) //< do not send message during storms { bool is_probe = (v.loaded ? v.GetCrewCount() == 0 : v.protoVessel.GetVesselCrew().Count == 0); Message.Post(Severity.warning, "Signal lost with <b>" + v.vesselName + "</b>", is_probe ? "Remote control disabled" : "Data transmission disabled"); } } else if (vd.msg_signal > 0 && ld.linked) { vd.msg_signal = 0; if (vd.cfg_signal == 1 && !Storm.JustEnded(v.mainBody, TimeWarp.deltaTime)) //< do not send messages after a storm { Message.Post(Severity.relax, "<b>" + v.vesselName + "</b> signal is back", ld.path.Count == 0 ? "We got a direct link with the space center" : "Relayed by <b>" + ld.path[ld.path.Count - 1] + "</b>"); } } } } }
void Problem_storm(Vessel v, ref List <Texture2D> icons, ref List <string> tooltips) { if (Storm.Incoming(v)) { icons.Add(Icons.storm_yellow); tooltips.Add(Lib.BuildString("Coronal mass ejection incoming <i>(", Lib.HumanReadableDuration(Storm.TimeBeforeCME(v)), ")</i>")); } if (Storm.InProgress(v)) { icons.Add(Icons.storm_red); tooltips.Add(Lib.BuildString("Solar storm in progress <i>(", Lib.HumanReadableDuration(Storm.TimeLeftCME(v)), ")</i>")); } }
void problem_storm(Vessel v, ref List<Texture> icons, ref List<string> tooltips) { if (Storm.Incoming(v.mainBody)) { icons.Add(icon_storm_warning); tooltips.Add("Coronal mass ejection incoming <i>(" + Lib.HumanReadableDuration(Storm.TimeBeforeCME(v.mainBody)) + ")</i>"); } if (Storm.InProgress(v.mainBody)) { icons.Add(icon_storm_danger); tooltips.Add("Solar storm in progress <i>(" + Lib.HumanReadableDuration(Storm.TimeLeftCME(v.mainBody)) + ")</i>"); } }
public static void update(Vessel v, vessel_info vi, VesselData vd, double elapsed_s) { // do nothing if signal mechanic is disabled if (!HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet && !RemoteTech.Enabled()) { return; } // get connection info ConnectionInfo conn = vi.connection; // maintain and send messages // - do not send messages for vessels without an antenna // - do not send messages during/after solar storms // - do not send messages for EVA kerbals if (conn.status != LinkStatus.no_antenna && !v.isEVA && v.situation != Vessel.Situations.PRELAUNCH) { if (!vd.msg_signal && !conn.linked) { vd.msg_signal = true; if (vd.cfg_signal && conn.status != LinkStatus.blackout) { string subtext = "Data transmission disabled"; if (vi.crew_count == 0) { switch (Settings.UnlinkedControl) { case UnlinkedCtrl.none: subtext = Localizer.Format("#KERBALISM_UI_noctrl"); break; case UnlinkedCtrl.limited: subtext = Localizer.Format("#KERBALISM_UI_limitedcontrol"); break; } } Message.Post(Severity.warning, Lib.BuildString(Localizer.Format("#KERBALISM_UI_signallost"), " <b>", v.vesselName, "</b>"), subtext); } } else if (vd.msg_signal && conn.linked) { vd.msg_signal = false; if (vd.cfg_signal && !Storm.JustEnded(v, elapsed_s)) { var path = conn.path; Message.Post(Severity.relax, Lib.BuildString("<b>", v.vesselName, "</b> ", Localizer.Format("#KERBALISM_UI_signalback")), path.Count == 0 ? Localizer.Format("#KERBALISM_UI_directlink") : Lib.BuildString(Localizer.Format("#KERBALISM_UI_relayby"), " <b>", path[path.Count - 1].vesselName, "</b>")); } } } }
public static void update(Vessel v, vessel_info vi, VesselData vd, double elapsed_s) { // do nothing if signal mechanic is disabled if (!Features.Signal) { return; } // get connection info ConnectionInfo conn = vi.connection; // maintain and send messages // - do not send messages for vessels without an antenna // - do not send messages during/after solar storms // - do not send messages for EVA kerbals if (conn.status != LinkStatus.no_antenna && !v.isEVA) { if (!vd.msg_signal && !conn.linked) { vd.msg_signal = true; if (vd.cfg_signal && conn.status != LinkStatus.blackout) { string subtext = "Data transmission disabled"; if (vi.crew_count == 0) { switch (Settings.UnlinkedControl) { case UnlinkedCtrl.none: subtext = "Remote control disabled"; break; case UnlinkedCtrl.limited: subtext = "Limited control available"; break; } } Message.Post(Severity.warning, Lib.BuildString("Signal lost with <b>", v.vesselName, "</b>"), subtext); } } else if (vd.msg_signal && conn.linked) { vd.msg_signal = false; if (vd.cfg_signal && !Storm.JustEnded(v, elapsed_s)) { var path = conn.path; Message.Post(Severity.relax, Lib.BuildString("<b>", v.vesselName, "</b> signal is back"), path.Count == 0 ? "We got a direct link with the space center" : Lib.BuildString("Relayed by <b>", path[path.Count - 1].vesselName, "</b>")); } } } }
void Problem_storm(Vessel v, ref List <Texture2D> icons, ref List <string> tooltips) { if (Storm.Incoming(v)) { icons.Add(Textures.storm_yellow); var bd = Lib.IsSun(v.mainBody) ? v.KerbalismData().stormData : DB.Storm(Lib.GetParentPlanet(v.mainBody).name); var tti = bd.storm_time - Planetarium.GetUniversalTime(); tooltips.Add(Lib.BuildString(Lib.Color(Local.Monitor_ejectionincoming, Lib.Kolor.Orange), "\n<i>", Local.Monitor_TimetoimpactCoronalmass, Lib.HumanReadableDuration(tti), "</i>")); //"Coronal mass ejection incoming"Time to impact: } if (Storm.InProgress(v)) { icons.Add(Textures.storm_red); var bd = Lib.IsSun(v.mainBody) ? v.KerbalismData().stormData : DB.Storm(Lib.GetParentPlanet(v.mainBody).name); var remainingDuration = bd.storm_time + bd.displayed_duration - Planetarium.GetUniversalTime(); tooltips.Add(Lib.BuildString(Lib.Color(Local.Monitor_Solarstorminprogress, Lib.Kolor.Red), "\n<i>", Local.Monitor_SolarstormRemaining, Lib.HumanReadableDuration(remainingDuration), "</i>")); //"Solar storm in progress"Remaining duration: } }
// return the total environent radiation at position specified public static double Compute(Vessel v, Vector3d position, double gamma_transparency, double sunlight, out bool blackout, out bool magnetosphere, out bool inner_belt, out bool outer_belt, out bool interstellar) { // prepare out parameters blackout = false; magnetosphere = false; inner_belt = false; outer_belt = false; interstellar = false; // no-op when Radiation is disabled if (!Features.Radiation) { return(0.0); } // store stuff Space gsm; Vector3 p; float D; // transform to local space once position = ScaledSpace.LocalToScaledSpace(position); // accumulate radiation double radiation = 0.0; CelestialBody body = v.mainBody; while (body != null) { RadiationBody rb = Info(body); RadiationModel mf = rb.model; if (mf.Has_field()) { // generate radii-normalized GSM space gsm = Gsm_space(rb.body, FlightGlobals.Bodies[rb.reference]); // move the poing in GSM space p = gsm.Transform_in(position); // accumulate radiation and determine pause/belt flags if (mf.has_inner) { D = mf.Inner_func(p); radiation += Lib.Clamp(D / -0.0666f, 0.0f, 1.0f) * rb.radiation_inner; inner_belt |= D < 0.0f; } if (mf.has_outer) { D = mf.Outer_func(p); radiation += Lib.Clamp(D / -0.0333f, 0.0f, 1.0f) * rb.radiation_outer; outer_belt |= D < 0.0f; } if (mf.has_pause) { D = mf.Pause_func(p); radiation += Lib.Clamp(D / -0.1332f, 0.0f, 1.0f) * rb.radiation_pause; magnetosphere |= D < 0.0f && rb.body.flightGlobalsIndex != 0; //< ignore heliopause interstellar |= D > 0.0f && rb.body.flightGlobalsIndex == 0; //< outside heliopause } } // avoid loops in the chain body = (body.referenceBody != null && body.referenceBody.referenceBody == body) ? null : body.referenceBody; } // add extern radiation radiation += PreferencesStorm.Instance.ExternRadiation; // add emitter radiation radiation += Emitter.Total(v); // if there is a storm in progress if (Storm.InProgress(v)) { // inside a magnetopause (except heliosphere), blackout the signal // outside, add storm radiations modulated by sun visibility if (magnetosphere) { blackout = true; } else { radiation += PreferencesStorm.Instance.StormRadiation * sunlight; } } // clamp radiation to positive range // note: we avoid radiation going to zero by using a small positive value radiation = Math.Max(radiation, Nominal); // return radiation, scaled by gamma transparency if inside atmosphere return(radiation * gamma_transparency); }
void FixedUpdate() { // remove control locks in any case Misc.clearLocks(); // do nothing if paused if (Lib.IsPaused()) { return; } // maintain elapsed_s, converting to double only once // and detect warp blending double fixedDeltaTime = TimeWarp.fixedDeltaTime; if (Math.Abs(fixedDeltaTime - elapsed_s) > double.Epsilon) { warp_blending = 0; } else { ++warp_blending; } elapsed_s = fixedDeltaTime; // evict oldest entry from vessel cache Cache.update(); // store info for oldest unloaded vessel double last_time = 0.0; Vessel last_v = null; vessel_info last_vi = null; VesselData last_vd = null; vessel_resources last_resources = null; // for each vessel foreach (Vessel v in FlightGlobals.Vessels) { // get vessel info from the cache vessel_info vi = Cache.VesselInfo(v); // set locks for active vessel if (v.isActiveVessel) { Misc.setLocks(v, vi); } // maintain eva dead animation and helmet state if (v.loaded && v.isEVA) { EVA.update(v); } // keep track of rescue mission kerbals, and gift resources to their vessels on discovery if (v.loaded && vi.is_vessel) { // manage rescue mission mechanics Misc.manageRescueMission(v); } // do nothing else for invalid vessels if (!vi.is_valid) { continue; } // get vessel data from db VesselData vd = DB.Vessel(v); // get resource cache vessel_resources resources = ResourceCache.Get(v); // if loaded if (v.loaded) { // show belt warnings Radiation.beltWarnings(v, vi, vd); // update storm data Storm.update(v, vi, vd, elapsed_s); // show signal warnings Signal.update(v, vi, vd, elapsed_s); // consume ec for transmission, and transmit science data Science.update(v, vi, vd, resources, elapsed_s); // apply rules Profile.Execute(v, vi, vd, resources, elapsed_s); // apply deferred requests resources.Sync(v, elapsed_s); // call automation scripts vd.computer.automate(v, vi, resources); // remove from unloaded data container unloaded.Remove(vi.id); } // if unloaded else { // get unloaded data, or create an empty one unloaded_data ud; if (!unloaded.TryGetValue(vi.id, out ud)) { ud = new unloaded_data(); unloaded.Add(vi.id, ud); } // accumulate time ud.time += elapsed_s; // maintain oldest entry if (ud.time > last_time) { last_time = ud.time; last_v = v; last_vi = vi; last_vd = vd; last_resources = resources; } } } // if the oldest unloaded vessel was selected if (last_v != null) { // show belt warnings Radiation.beltWarnings(last_v, last_vi, last_vd); // update storm data Storm.update(last_v, last_vi, last_vd, last_time); // show signal warnings Signal.update(last_v, last_vi, last_vd, last_time); // consume ec for transmission, and transmit science Science.update(last_v, last_vi, last_vd, last_resources, last_time); // apply rules Profile.Execute(last_v, last_vi, last_vd, last_resources, last_time); // simulate modules in background Background.update(last_v, last_vi, last_vd, last_resources, last_time); // apply deferred requests last_resources.Sync(last_v, last_time); // call automation scripts last_vd.computer.automate(last_v, last_vi, last_resources); // remove from unloaded data container unloaded.Remove(last_vi.id); } // update storm data for one body per-step if (storm_bodies.Count > 0) { storm_bodies.ForEach(k => k.time += elapsed_s); storm_data sd = storm_bodies[storm_index]; Storm.update(sd.body, sd.time); sd.time = 0.0; storm_index = (storm_index + 1) % storm_bodies.Count; } }
void FixedUpdate() { // remove control locks in any case Misc.ClearLocks(); // do nothing if paused if (Lib.IsPaused()) { return; } // maintain elapsed_s, converting to double only once // and detect warp blending double fixedDeltaTime = TimeWarp.fixedDeltaTime; if (Math.Abs(fixedDeltaTime - elapsed_s) > double.Epsilon) { warp_blending = 0; } else { ++warp_blending; } elapsed_s = fixedDeltaTime; // evict oldest entry from vessel cache Cache.Update(); // vvvv------- This code tests for a theroy that could cause #313 // If KSP itself has the same vessel more than once in the // FlightGlobals.Vessels list, it would cause processes to run too many times. // The other possible cause was a Vessel ID collision in Lib.VesselID(), which // only used 4 bytes of a 16 byte GUID to create an ID from. // // If the BUG TRIGGERED message is never observed in the wild, // it is safe to remove this chunk of code. Dictionary <UInt64, Vessel> vessels = new Dictionary <UInt64, Vessel>(); foreach (Vessel v in FlightGlobals.Vessels) { if (vessels.ContainsKey(Lib.VesselID(v))) { Lib.Log("THIS SHOULD NOT BE HAPPENING: Vessel " + v.name + " already seen in FlightGlobals.Vessels"); Message.Post(Lib.BuildString(Lib.Color("red", "BUG TRIGGERED", true), "\n", v.name + " duplicated in FlightGlobals.Vessels. Please report this on GitHub.")); } else { vessels.Add(Lib.VesselID(v), v); } } // ^^^^-------- end theory test code // store info for oldest unloaded vessel double last_time = 0.0; Vessel last_v = null; Vessel_info last_vi = null; VesselData last_vd = null; Vessel_resources last_resources = null; // for each vessel //foreach (Vessel v in FlightGlobals.Vessels) foreach (Vessel v in vessels.Values) { // get vessel info from the cache Vessel_info vi = Cache.VesselInfo(v); // set locks for active vessel if (v.isActiveVessel) { Misc.SetLocks(v, vi); } // maintain eva dead animation and helmet state if (v.loaded && v.isEVA) { EVA.Update(v); } // keep track of rescue mission kerbals, and gift resources to their vessels on discovery if (v.loaded && vi.is_vessel) { // manage rescue mission mechanics Misc.ManageRescueMission(v); } // do nothing else for invalid vessels if (!vi.is_valid) { continue; } // get vessel data from db VesselData vd = DB.Vessel(v); // get resource cache Vessel_resources resources = ResourceCache.Get(v); // if loaded if (v.loaded) { // get most used resource Resource_info ec = resources.Info(v, "ElectricCharge"); // show belt warnings Radiation.BeltWarnings(v, vi, vd); // update storm data Storm.Update(v, vi, vd, elapsed_s); Communications.Update(v, vi, vd, ec, elapsed_s); // Habitat equalization ResourceBalance.Equalizer(v); // transmit science data Science.Update(v, vi, vd, resources, elapsed_s); // apply rules Profile.Execute(v, vi, vd, resources, elapsed_s); // apply deferred requests resources.Sync(v, elapsed_s); // call automation scripts vd.computer.Automate(v, vi, resources); // remove from unloaded data container unloaded.Remove(vi.id); } // if unloaded else { // get unloaded data, or create an empty one Unloaded_data ud; if (!unloaded.TryGetValue(vi.id, out ud)) { ud = new Unloaded_data(); unloaded.Add(vi.id, ud); } // accumulate time ud.time += elapsed_s; // maintain oldest entry if (ud.time > last_time) { last_time = ud.time; last_v = v; last_vi = vi; last_vd = vd; last_resources = resources; } } } // at most one vessel gets background processing per physics tick // if there is a vessel that is not the currently loaded vessel, then // we will update the vessel whose most recent background update is the oldest if (last_v != null) { // get most used resource Resource_info last_ec = last_resources.Info(last_v, "ElectricCharge"); // show belt warnings Radiation.BeltWarnings(last_v, last_vi, last_vd); // update storm data Storm.Update(last_v, last_vi, last_vd, last_time); Communications.Update(last_v, last_vi, last_vd, last_ec, last_time); // transmit science data Science.Update(last_v, last_vi, last_vd, last_resources, last_time); // apply rules Profile.Execute(last_v, last_vi, last_vd, last_resources, last_time); // simulate modules in background Background.Update(last_v, last_vi, last_vd, last_resources, last_time); // apply deferred requests last_resources.Sync(last_v, last_time); // call automation scripts last_vd.computer.Automate(last_v, last_vi, last_resources); // remove from unloaded data container unloaded.Remove(last_vi.id); } // update storm data for one body per-step if (storm_bodies.Count > 0) { storm_bodies.ForEach(k => k.time += elapsed_s); Storm_data sd = storm_bodies[storm_index]; Storm.Update(sd.body, sd.time); sd.time = 0.0; storm_index = (storm_index + 1) % storm_bodies.Count; } }
private void EvaluateEnvironment(double elapsedSeconds) { UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.EvaluateStatus"); // we use analytic mode if more than 2 minutes of game time has passed since last evaluation (~ x6000 timewarp speed) isAnalytic = elapsedSeconds > 120.0; // get vessel position Vector3d position = Lib.VesselPosition(Vessel); // this should never happen again if (Vector3d.Distance(position, Vessel.mainBody.position) < 1.0) { throw new Exception("Shit hit the fan for vessel " + Vessel.vesselName); } // situation underwater = Sim.Underwater(Vessel); breathable = Sim.Breathable(Vessel, EnvUnderwater); landed = Lib.Landed(Vessel); inAtmosphere = Vessel.mainBody.atmosphere && Vessel.altitude < Vessel.mainBody.atmosphereDepth; zeroG = !EnvLanded && !inAtmosphere; visibleBodies = Sim.GetLargeBodies(position); // get solar info (with multiple stars / Kopernicus support) // get the 'visibleBodies' and 'sunsInfo' lists, the 'mainSun', 'solarFluxTotal' variables. // require the situation variables to be evaluated first UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.Sunlight"); SunInfo.UpdateSunsInfo(this, position); UnityEngine.Profiling.Profiler.EndSample(); sunBodyAngle = Sim.SunBodyAngle(Vessel, position, mainSun.SunData.body); // temperature at vessel position UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.Temperature"); temperature = Sim.Temperature(Vessel, position, solarFluxTotal, out albedoFlux, out bodyFlux, out totalFlux); tempDiff = Sim.TempDiff(EnvTemperature, Vessel.mainBody, EnvLanded); UnityEngine.Profiling.Profiler.EndSample(); // radiation UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.Radiation"); gammaTransparency = Sim.GammaTransparency(Vessel.mainBody, Vessel.altitude); bool new_innerBelt, new_outerBelt, new_magnetosphere; radiation = Radiation.Compute(Vessel, position, EnvGammaTransparency, mainSun.SunlightFactor, out blackout, out new_magnetosphere, out new_innerBelt, out new_outerBelt, out interstellar, out shieldedRadiation); if (new_innerBelt != innerBelt || new_outerBelt != outerBelt || new_magnetosphere != magnetosphere) { innerBelt = new_innerBelt; outerBelt = new_outerBelt; magnetosphere = new_magnetosphere; if (Evaluated) { API.OnRadiationFieldChanged.Notify(Vessel, innerBelt, outerBelt, magnetosphere); } } UnityEngine.Profiling.Profiler.EndSample(); thermosphere = Sim.InsideThermosphere(Vessel); exosphere = Sim.InsideExosphere(Vessel); inStorm = Storm.InProgress(Vessel); vesselSituations.Update(); // other stuff gravioli = Sim.Graviolis(Vessel); UnityEngine.Profiling.Profiler.EndSample(); }
// hook: StormIncoming() public static bool hook_StormIncoming(Vessel v) { return(Cache.VesselInfo(v).is_valid&& Storm.Incoming(v)); }
// return the total environent radiation at position specified public static double Compute(Vessel v, Vector3d position, double gamma_transparency, double sunlight, out bool blackout, out bool magnetosphere, out bool inner_belt, out bool outer_belt, out bool interstellar, out double shieldedRadiation) { // prepare out parameters blackout = false; magnetosphere = false; inner_belt = false; outer_belt = false; interstellar = false; shieldedRadiation = 0.0; // no-op when Radiation is disabled if (!Features.Radiation) { return(0.0); } // store stuff Space gsm; Vector3 p; double D; double r; // accumulate radiation double radiation = 0.0; CelestialBody body = v.mainBody; while (body != null) { // Compute radiation values from overlapping 3d fields (belts + magnetospheres) RadiationBody rb = Info(body); RadiationModel mf = rb.model; // activity is [-0.15..1.05] var activity = rb.SolarActivity(false); if (mf.Has_field()) { // transform to local space once var scaled_position = ScaledSpace.LocalToScaledSpace(position); // generate radii-normalized GSM space gsm = Gsm_space(rb, true); // move the point in GSM space p = gsm.Transform_in(scaled_position); // accumulate radiation and determine pause/belt flags if (mf.has_inner) { D = mf.Inner_func(p); inner_belt |= D < 0; // allow for radiation field to grow/shrink with solar activity D -= activity * 0.25 / mf.inner_radius; r = RadiationInBelt(D, mf.inner_radius, rb.radiation_inner_gradient); radiation += r * rb.radiation_inner * (1 + activity * 0.3); } if (mf.has_outer) { D = mf.Outer_func(p); outer_belt |= D < 0; // allow for radiation field to grow/shrink with solar activity D -= activity * 0.25 / mf.outer_radius; r = RadiationInBelt(D, mf.outer_radius, rb.radiation_outer_gradient); radiation += r * rb.radiation_outer * (1 + activity * 0.3); } if (mf.has_pause) { gsm = Gsm_space(rb, false); p = gsm.Transform_in(scaled_position); D = mf.Pause_func(p); radiation += Lib.Clamp(D / -0.1332f, 0.0f, 1.0f) * rb.RadiationPause(); magnetosphere |= D < 0.0f && !Lib.IsSun(rb.body); //< ignore heliopause interstellar |= D > 0.0f && Lib.IsSun(rb.body); //< outside heliopause } } if (rb.radiation_surface > 0 && body != v.mainBody) { Vector3d direction; double distance; if (Sim.IsBodyVisible(v, position, body, v.KerbalismData().EnvVisibleBodies, out direction, out distance)) { var r0 = RadiationR0(rb); var r1 = DistanceRadiation(r0, distance); // clamp to max. surface radiation. when loading on a rescaled system, the vessel can appear to be within the sun for a few ticks radiation += Math.Min(r1, rb.radiation_surface); #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " from surface of " + body + ": " + Lib.HumanReadableRadiation(radiation) + " gamma: " + Lib.HumanReadableRadiation(r1)); } #endif } } // avoid loops in the chain body = (body.referenceBody != null && body.referenceBody.referenceBody == body) ? null : body.referenceBody; } // add extern radiation radiation += Settings.ExternRadiation / 3600.0; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " extern: " + Lib.HumanReadableRadiation(radiation) + " gamma: " + Lib.HumanReadableRadiation(Settings.ExternRadiation)); } #endif // apply gamma transparency if inside atmosphere radiation *= gamma_transparency; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " after gamma: " + Lib.HumanReadableRadiation(radiation) + " transparency: " + gamma_transparency); } #endif // add surface radiation of the body itself if (Lib.IsSun(v.mainBody) && v.altitude < v.mainBody.Radius) { if (v.altitude > v.mainBody.Radius) { radiation += DistanceRadiation(RadiationR0(Info(v.mainBody)), v.altitude); } } #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " from current main body: " + Lib.HumanReadableRadiation(radiation) + " gamma: " + Lib.HumanReadableRadiation(DistanceRadiation(RadiationR0(Info(v.mainBody)), v.altitude))); } #endif shieldedRadiation = radiation; // if there is a storm in progress if (Storm.InProgress(v)) { // inside a magnetopause (except heliosphere), blackout the signal // outside, add storm radiations modulated by sun visibility if (magnetosphere) { blackout = true; } else { var vd = v.KerbalismData(); var activity = Info(vd.EnvMainSun.SunData.body).SolarActivity(false) / 2.0; var strength = PreferencesRadiation.Instance.StormRadiation * sunlight * (activity + 0.5); radiation += strength; shieldedRadiation += vd.EnvHabitatInfo.AverageHabitatRadiation(strength); } } // add emitter radiation after atmosphere transparency var emitterRadiation = Emitter.Total(v); radiation += emitterRadiation; shieldedRadiation += emitterRadiation; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " after emitters: " + Lib.HumanReadableRadiation(radiation) + " shielded " + Lib.HumanReadableRadiation(shieldedRadiation)); } #endif // for EVAs, add the effect of nearby emitters if (v.isEVA) { var nearbyEmitters = Emitter.Nearby(v); radiation += nearbyEmitters; shieldedRadiation += nearbyEmitters; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " nearby emitters " + Lib.HumanReadableRadiation(nearbyEmitters)); } #endif } var passiveShielding = PassiveShield.Total(v); shieldedRadiation -= passiveShielding; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " passiveShielding " + Lib.HumanReadableRadiation(passiveShielding)); } if (v.loaded) { Lib.Log("Radiation " + v + " before clamp: " + Lib.HumanReadableRadiation(radiation) + " shielded " + Lib.HumanReadableRadiation(shieldedRadiation)); } #endif // clamp radiation to positive range // note: we avoid radiation going to zero by using a small positive value radiation = Math.Max(radiation, Nominal); shieldedRadiation = Math.Max(shieldedRadiation, Nominal); #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " after clamp: " + Lib.HumanReadableRadiation(radiation) + " shielded " + Lib.HumanReadableRadiation(shieldedRadiation)); } #endif // return radiation return(radiation); }
void FixedUpdate() { // remove control locks in any case Misc.ClearLocks(); // do nothing if paused if (Lib.IsPaused()) { return; } // convert elapsed time to double only once double fixedDeltaTime = TimeWarp.fixedDeltaTime; // and detect warp blending if (Math.Abs(fixedDeltaTime - elapsed_s) < 0.001) { warp_blending = 0; } else { ++warp_blending; } // update elapsed time elapsed_s = fixedDeltaTime; // store info for oldest unloaded vessel double last_time = 0.0; Guid last_id = Guid.Empty; Vessel last_v = null; VesselData last_vd = null; VesselResources last_resources = null; foreach (VesselData vd in DB.VesselDatas) { vd.EarlyUpdate(); } // for each vessel foreach (Vessel v in FlightGlobals.Vessels) { // get vessel data VesselData vd = v.KerbalismData(); // update the vessel data validity vd.Update(v); // set locks for active vessel if (v.isActiveVessel) { Misc.SetLocks(v); } // maintain eva dead animation and helmet state if (v.loaded && v.isEVA) { EVA.Update(v); } // keep track of rescue mission kerbals, and gift resources to their vessels on discovery if (v.loaded && vd.is_vessel) { // manage rescue mission mechanics Misc.ManageRescueMission(v); } // do nothing else for invalid vessels if (!vd.IsSimulated) { continue; } // get resource cache VesselResources resources = ResourceCache.Get(v); // if loaded if (v.loaded) { //UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.VesselDataEval"); // update the vessel info vd.Evaluate(false, elapsed_s); //UnityEngine.Profiling.Profiler.EndSample(); // get most used resource ResourceInfo ec = resources.GetResource(v, "ElectricCharge"); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Radiation"); // show belt warnings Radiation.BeltWarnings(v, vd); // update storm data Storm.Update(v, vd, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Comms"); Communications.Update(v, vd, ec, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); // Habitat equalization ResourceBalance.Equalizer(v); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Science"); // transmit science data Science.Update(v, vd, ec, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Profile"); // apply rules Profile.Execute(v, vd, resources, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Profile"); // part module resource updates vd.ResourceUpdate(resources, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Resource"); // apply deferred requests resources.Sync(v, vd, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); // call automation scripts vd.computer.Automate(v, vd, resources); // remove from unloaded data container unloaded.Remove(vd.VesselId); } // if unloaded else { // get unloaded data, or create an empty one Unloaded_data ud; if (!unloaded.TryGetValue(vd.VesselId, out ud)) { ud = new Unloaded_data(); unloaded.Add(vd.VesselId, ud); } // accumulate time ud.time += elapsed_s; // maintain oldest entry if (ud.time > last_time) { last_time = ud.time; last_v = v; last_vd = vd; last_resources = resources; } } } // at most one vessel gets background processing per physics tick : // if there is a vessel that is not the currently loaded vessel, then // we will update the vessel whose most recent background update is the oldest if (last_v != null) { //UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.VesselDataEval"); // update the vessel info (high timewarp speeds reevaluation) last_vd.Evaluate(false, last_time); //UnityEngine.Profiling.Profiler.EndSample(); // get most used resource ResourceInfo last_ec = last_resources.GetResource(last_v, "ElectricCharge"); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Radiation"); // show belt warnings Radiation.BeltWarnings(last_v, last_vd); // update storm data Storm.Update(last_v, last_vd, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Comms"); Communications.Update(last_v, last_vd, last_ec, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Profile"); // apply rules Profile.Execute(last_v, last_vd, last_resources, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Background"); // simulate modules in background Background.Update(last_v, last_vd, last_resources, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Science"); // transmit science data Science.Update(last_v, last_vd, last_ec, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Resource"); // apply deferred requests last_resources.Sync(last_v, last_vd, last_time); UnityEngine.Profiling.Profiler.EndSample(); // call automation scripts last_vd.computer.Automate(last_v, last_vd, last_resources); // remove from unloaded data container unloaded.Remove(last_vd.VesselId); } // update storm data for one body per-step if (storm_bodies.Count > 0) { storm_bodies.ForEach(k => k.time += elapsed_s); Storm_data sd = storm_bodies[storm_index]; Storm.Update(sd.body, sd.time); sd.time = 0.0; storm_index = (storm_index + 1) % storm_bodies.Count; } }
public override void OnLoad(ConfigNode node) { // everything in there will be called only one time : the first time a game is loaded from the main menu if (!IsCoreGameInitDone) { // core game systems Sim.Init(); // find suns (Kopernicus support) Radiation.Init(); // create the radiation fields ScienceDB.Init(); // build the science database (needs Sim.Init() and Radiation.Init() first) Science.Init(); // register the science hijacker // static graphic components LineRenderer.Init(); ParticleRenderer.Init(); Highlighter.Init(); // UI Textures.Init(); // set up the icon textures UI.Init(); // message system, main gui, launcher KsmGui.KsmGuiMasterController.Init(); // setup the new gui framework // part prefabs hacks Profile.SetupPods(); // add supply resources to pods Misc.TweakPartIcons(); // various tweaks to the part icons in the editor // Create KsmGui windows new ScienceArchiveWindow(); // GameEvents callbacks Callbacks = new Callbacks(); IsCoreGameInitDone = true; } // everything in there will be called every time a savegame (or a new game) is loaded from the main menu if (!IsSaveGameInitDone) { Cache.Init(); ResourceCache.Init(); // prepare storm data foreach (CelestialBody body in FlightGlobals.Bodies) { if (Storm.Skip_body(body)) { continue; } Storm_data sd = new Storm_data { body = body }; storm_bodies.Add(sd); } IsSaveGameInitDone = true; } // eveything else will be called on every OnLoad() call : // - save/load // - every scene change // - in various semi-random situations (thanks KSP) // Fix for background IMGUI textures being dropped on scene changes since KSP 1.8 Styles.ReloadBackgroundStyles(); // always clear the caches Cache.Clear(); ResourceCache.Clear(); // deserialize our database UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.DB.Load"); DB.Load(node); UnityEngine.Profiling.Profiler.EndSample(); // I'm smelling the hacky mess in here. Communications.NetworkInitialized = false; Communications.NetworkInitializing = false; // detect if this is a different savegame if (DB.uid != savegame_uid) { // clear caches Message.all_logs.Clear(); // sync main window pos from db UI.Sync(); // remember savegame id savegame_uid = DB.uid; } Kerbalism.gameLoadTime = Time.time; }
// return solar storm radiation hitting the vessel, in rad/s public static double StormRadiation(Vessel v, bool sunlight) { double storm_k = Storm.InProgress(v.mainBody) && !InsideMagnetosphere(v) && sunlight ? 1.0 : 0.0; return(Settings.StormRadiation * storm_k); }
// hook: StormInProgress() public static bool hook_StormInProgress(Vessel v) { return(Cache.VesselInfo(v).is_valid&& Storm.InProgress(v)); }
// return true if vessel is inside a magnetosphere and there is a storm in progress public static bool Blackout(Vessel v) { return(Storm.InProgress(v.mainBody) && Radiation.InsideMagnetosphere(v)); }