public static void BackgroundUpdate(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Reliability reliability) { // if it has not malfunctioned if (!Lib.Proto.GetBool(m, "broken")) { // get time of next failure double next = Lib.Proto.GetDouble(m, "next"); // get quality bool quality = Lib.Proto.GetBool(m, "quality"); // calculate epoch of failure if necessary if (next <= double.Epsilon) { double last = Planetarium.GetUniversalTime(); next = last + reliability.mtbf * (quality ? Settings.QualityScale : 1.0) * 2.0 * Lib.RandomDouble(); Lib.Proto.Set(m, "last", last); Lib.Proto.Set(m, "next", next); } // if it has failed, trigger malfunction if (Planetarium.GetUniversalTime() > next) { ProtoBreak(v, p, m); } } }
// render the fields of the interesting body public static void Render() { // get interesting body CelestialBody body = Interesting_body(); // maintain visualization modes if (body == null) { show_inner = false; show_outer = false; show_pause = false; } else { if (Input.GetKeyDown(KeyCode.Keypad0)) { if (show_inner || show_outer || show_pause) { show_inner = false; show_outer = false; show_pause = false; } else { show_inner = true; show_outer = true; show_pause = true; } } if (Input.GetKeyDown(KeyCode.Keypad1)) { show_inner = true; show_outer = false; show_pause = false; } if (Input.GetKeyDown(KeyCode.Keypad2)) { show_inner = false; show_outer = true; show_pause = false; } if (Input.GetKeyDown(KeyCode.Keypad3)) { show_inner = false; show_outer = false; show_pause = true; } } // if there is an active body, and at least one of the modes is active if (body != null && (show_inner || show_outer || show_pause)) { // if we don't know if preprocessing is completed if (preprocess_thread != null) { // if the preprocess thread has not done yet if (preprocess_thread.IsAlive) { // disable all modes show_inner = false; show_outer = false; show_pause = false; // tell the user and do nothing Message.Post("<color=#00ffff><b>Fitting particles to signed distance fields</b></color>", "Come back in a minute"); return; } // wait for particle-fitting thread to cleanup preprocess_thread.Join(); // preprocessing is complete preprocess_thread = null; } // load and configure shader if (mat == null) { if (!Settings.LowQualityRendering) { // load shader mat = Lib.GetShader("MiniParticle"); // configure shader mat.SetColor("POINT_COLOR", new Color(0.33f, 0.33f, 0.33f, 0.1f)); } else { // load shader mat = Lib.GetShader("PointParticle"); // configure shader mat.SetColor("POINT_COLOR", new Color(0.33f, 0.33f, 0.33f, 0.1f)); mat.SetFloat("POINT_SIZE", 4.0f); } } // generate radii-normalized GMS space RadiationBody rb = Info(body); Space gsm = Gsm_space(rb.body, FlightGlobals.Bodies[rb.reference]); // [debug] show axis //LineRenderer.commit(gsm.origin, gsm.origin + gsm.x_axis * gsm.scale * 5.0f, Color.red); //LineRenderer.commit(gsm.origin, gsm.origin + gsm.y_axis * gsm.scale * 5.0f, Color.green); //LineRenderer.commit(gsm.origin, gsm.origin + gsm.z_axis * gsm.scale * 5.0f, Color.blue); // get magnetic field data RadiationModel mf = Info(body).model; // enable material mat.SetPass(0); // render active body fields Matrix4x4 m = gsm.Look_at(); if (show_inner && mf.has_inner) { mf.inner_pmesh.Render(m); } if (show_outer && mf.has_outer) { mf.outer_pmesh.Render(m); } if (show_pause && mf.has_pause) { mf.pause_pmesh.Render(m); } } }
static void Render_ConnectionDetail(Panel p, double range, double rate, short freq) { // render frequency string detail = Lib.BuildString("<size=10>", Lib.HumanReadableRange(range), "</size>"); p.SetContent(Lib.BuildString("Frequency: <b>", freq.ToString(), "</b>"), detail, Lib.BuildString("<b>", Lib.HumanReadableDataRate(rate), "</b>")); }
public static void StartScan(PartModule scanner) { Lib.ReflectionCall(scanner, "startScan"); }
// pseudo-ctor public static void Init() { // if radiation is disabled if (!Features.Radiation) { // create default environments for all planets foreach (CelestialBody body in FlightGlobals.Bodies) { bodies.Add(body.bodyName, new RadiationBody(body)); } // and do nothing else return; } // parse RadiationModel var rad_nodes = Lib.ParseConfigs("RadiationModel"); foreach (var rad_node in rad_nodes) { string name = Lib.ConfigValue(rad_node, "name", ""); if (!models.ContainsKey(name)) { models.Add(name, new RadiationModel(rad_node)); } } // parse RadiationBody var body_nodes = Lib.ParseConfigs("RadiationBody"); foreach (var body_node in body_nodes) { string name = Lib.ConfigValue(body_node, "name", ""); if (!bodies.ContainsKey(name)) { CelestialBody body = FlightGlobals.Bodies.Find(k => k.bodyName == name); if (body == null) { continue; // skip non-existing bodies } bodies.Add(name, new RadiationBody(body_node, models, body)); } } // create body environments for all the other planets foreach (CelestialBody body in FlightGlobals.Bodies) { if (!bodies.ContainsKey(body.bodyName)) { bodies.Add(body.bodyName, new RadiationBody(body)); } } // remove unused models List <string> to_remove = new List <string>(); foreach (var rad_pair in models) { bool used = false; foreach (var body_pair in bodies) { if (body_pair.Value.model == rad_pair.Value) { used = true; break; } } if (!used) { to_remove.Add(rad_pair.Key); } } foreach (string s in to_remove) { models.Remove(s); } // start particle-fitting thread preprocess_thread = new Thread(Preprocess) { Name = "particle-fitting", IsBackground = true }; preprocess_thread.Start(); }
public static double Volume_per_crew(Vessel v) { // living space is the volume per-capita normalized against an 'ideal living space' and clamped in an acceptable range return(Tot_volume(v) / Math.Max(1, Lib.CrewCount(v))); }
[KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "[Debug] log volume/surface", active = false, groupName = "Habitat", groupDisplayName = "#KERBALISM_Group_Habitat")] //Habitat public void LogVolumeAndSurface() { Lib.GetPartVolumeAndSurface(part, true); }
// specifics support public Specifics Specs() { Specifics specs = new Specifics(); specs.Add("Volume", Lib.HumanReadableVolume(volume > double.Epsilon ? volume : Lib.PartVolume(part))); specs.Add("Surface", Lib.HumanReadableSurface(surface > double.Epsilon ? surface : Lib.PartSurface(part))); specs.Add("Pressurized", max_pressure >= Settings.PressureThreshold ? "yes" : "no"); if (inflate.Length > 0) { specs.Add("Inflatable", "yes"); } if (PhysicsGlobals.KerbalCrewMass > 0) { specs.Add("Added mass per crew", Lib.HumanReadableMass(PhysicsGlobals.KerbalCrewMass)); } return(specs); }
// return a verbose description of shielding capability public static string Shielding_to_string(double v) { return(v <= double.Epsilon ? "none" : Lib.BuildString((20.0 * v / PreferencesStorm.Instance.shieldingEfficiency).ToString("F2"), " mm Pb")); }
public SupplyData(ConfigNode node) { message = Lib.ConfigValue(node, "message", 0u); }
public AntennaInfoRT(Vessel v, bool powered, bool storm) { RemoteTech.SetPoweredDown(v.id, !powered); RemoteTech.SetCommsBlackout(v.id, storm); // if vessel is loaded, don't calculate ec, RT already handle it. if (v.loaded) { // find transmitters foreach (Part p in v.parts) { foreach (PartModule m in p.Modules) { // calculate internal (passive) transmitter ec usage @ 0.5W each if (m.moduleName == "ModuleRTAntennaPassive") { ec += 0.0005; } // calculate external transmitters else if (m.moduleName == "ModuleRTAntenna") { // only include data rate and ec cost if transmitter is active if (Lib.ReflectionValue <bool>(m, "IsRTActive")) { rate += (Lib.ReflectionValue <float>(m, "RTPacketSize") / Lib.ReflectionValue <float>(m, "RTPacketInterval")); } } } } } // if vessel is not loaded else { // find proto transmitters foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots) { // get part prefab (required for module properties) Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab; foreach (ProtoPartModuleSnapshot m in p.modules) { // calculate internal (passive) transmitter ec usage @ 0.5W each if (m.moduleName == "ModuleRTAntennaPassive") { ec += 0.0005; } // calculate external transmitters else if (m.moduleName == "ModuleRTAntenna") { // only include data rate and ec cost if transmitter is active if (Lib.Proto.GetBool(m, "IsRTActive")) { bool mFound = false; // get all modules in prefab foreach (PartModule pm in part_prefab.Modules) { if (pm.moduleName == m.moduleName) { mFound = true; ModuleResource mResource = pm.resHandler.inputResources.Find(r => r.name == "ElectricCharge"); float? packet_size = Lib.SafeReflectionValue <float>(pm, "RTPacketSize"); float? packet_Interval = Lib.SafeReflectionValue <float>(pm, "RTPacketInterval"); // workaround for old savegames if (mResource == null || packet_size == null || packet_Interval == null) { Lib.DebugLog("Old SaveGame PartModule ModuleRTAntenna for part '{0}' on unloaded vessel '{1}', using default values as a workaround", p.partName, v.vesselName); Lib.DebugLog("ElectricCharge isNull: '{0}', RTPacketSize isNull: '{1}', RTPacketInterval isNull: '{2}'", mResource == null, packet_size == null, packet_Interval == null); rate += 6.6666; // 6.67 Mb/s in 100% factor ec += 0.025; // 25 W/s } else { rate += (float)packet_size / (float)packet_Interval; ec += mResource.rate; } } } if (!mFound) { Lib.DebugLog("Could not find PartModule ModuleRTAntenna for part {0} on unloaded vessel {1}, using default values as a workaround", p.partName, v.vesselName); rate += 6.6666; // 6.67 Mb/s in 100% factor ec += 0.025; // 25 W/s } } } } } } Init(v, powered, storm); }
// module info support public string GetModuleTitle() { return(Lib.BuildString(title, " Reliability")); }
public static void ProtoBreak(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m) { // get reliability module prefab string type = Lib.Proto.GetString(m, "type", string.Empty); Reliability reliability = p.partPrefab.FindModulesImplementing <Reliability>().Find(k => k.type == type); if (reliability == null) { return; } // if manned, or if safemode didn't trigger if (Cache.VesselInfo(v).crew_capacity > 0 || Lib.RandomDouble() > Settings.SafeModeChance) { // flag as broken Lib.Proto.Set(m, "broken", true); // determine if this is a critical failure bool critical = Lib.RandomDouble() < Settings.CriticalChance; Lib.Proto.Set(m, "critical", critical); // for each associated module foreach (var proto_module in p.modules.FindAll(k => k.moduleName == reliability.type)) { // disable the module Lib.Proto.Set(proto_module, "isEnabled", false); } // type-specific hacks switch (reliability.type) { case "ProcessController": foreach (ProcessController pc in p.partPrefab.FindModulesImplementing <ProcessController>()) { ProtoPartResourceSnapshot res = p.resources.Find(k => k.resourceName == pc.resource); if (res != null) { res.flowState = false; } } break; } // show message broken_msg(v, reliability.title, critical); } // safe mode else { // reset age Lib.Proto.Set(m, "last", 0.0); Lib.Proto.Set(m, "next", 0.0); // notify user safemode_msg(v, reliability.title); } // in any case, incentive redundancy if (Settings.IncentiveRedundancy) { incentive_redundancy(v, reliability.redundancy); } }
public void Repair() { // disable for dead eva kerbals Vessel v = FlightGlobals.ActiveVessel; if (v == null || EVA.IsDead(v)) { return; } // check trait if (!repair_cs.check(v)) { Message.Post ( Lib.TextVariant ( "I'm not qualified for this", "I will not even know where to start", "I'm afraid I can't do that" ), repair_cs.warning() ); return; } // flag as not broken broken = false; // reset times last = 0.0; next = 0.0; // re-enable module foreach (PartModule m in modules) { m.isEnabled = true; m.enabled = true; } // we need to reconfigure the module here, because if all modules of a type // share the broken state, and these modules are part of a configure setup, // then repairing will enable all of them, messing up with the configuration part.FindModulesImplementing <Configure>().ForEach(k => k.configure()); // type-specific hacks apply(false); // notify user Message.Post ( Lib.BuildString("<b>", title, "</b> repaired"), Lib.TextVariant ( "A powerkick did the trick", "Duct tape, is there something it can't fix?", "Fully operational again", "We are back in business" ) ); }
// specifics support public Specifics Specs() { Specifics specs = new Specifics(); specs.Add(Local.Habitat_info1, Lib.HumanReadableVolume(volume > 0.0 ? volume : Lib.PartBoundsVolume(part)) + (volume > 0.0 ? "" : " (bounds)")); //"Volume" specs.Add(Local.Habitat_info2, Lib.HumanReadableSurface(surface > 0.0 ? surface : Lib.PartBoundsSurface(part)) + (surface > 0.0 ? "" : " (bounds)")); //"Surface" specs.Add(Local.Habitat_info3, max_pressure >= Settings.PressureThreshold ? Local.Habitat_yes : Local.Habitat_no); //"Pressurized""yes""no" if (inflate.Length > 0) { specs.Add(Local.Habitat_info4, Local.Habitat_yes); //"Inflatable""yes" } if (PhysicsGlobals.KerbalCrewMass > 0) { specs.Add(Local.Habitat_info5, Lib.HumanReadableMass(PhysicsGlobals.KerbalCrewMass));//"Added mass per crew" } return(specs); }
static Styles() { blackBackground = Lib.GetTexture("black-background"); // window container win = new GUIStyle(HighLogic.Skin.window) { padding = { left = ScaleInteger(6), right = ScaleInteger(6), top = 0, bottom = 0 } }; // window title container title_container = new GUIStyle { stretchWidth = true, fixedHeight = ScaleFloat(16.0f), margin = { bottom = ScaleInteger(2), top = ScaleInteger(2) } }; // window title text title_text = new GUIStyle { fontStyle = FontStyle.Bold, fontSize = ScaleInteger(10), fixedHeight = ScaleFloat(16.0f), alignment = TextAnchor.MiddleCenter }; // subsection title container section_container = new GUIStyle { stretchWidth = true, fixedHeight = ScaleFloat(16.0f), normal = { background = blackBackground }, margin = { bottom = ScaleInteger(4), top = ScaleInteger(4) } }; // subsection title text section_text = new GUIStyle(HighLogic.Skin.label) { stretchWidth = true, stretchHeight = true, fontSize = ScaleInteger(12), alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.white } }; // entry row container entry_container = new GUIStyle { stretchWidth = true, fixedHeight = ScaleFloat(16.0f) }; // entry label text entry_label = new GUIStyle(HighLogic.Skin.label) { richText = true, stretchWidth = true, stretchHeight = true, fontSize = ScaleInteger(12), alignment = TextAnchor.MiddleLeft, normal = { textColor = Color.white } }; entry_label_nowrap = new GUIStyle(HighLogic.Skin.label) { richText = true, wordWrap = false, stretchWidth = true, stretchHeight = true, fontSize = ScaleInteger(12), alignment = TextAnchor.MiddleLeft, normal = { textColor = Color.white } }; // entry value text entry_value = new GUIStyle(HighLogic.Skin.label) { richText = true, stretchWidth = true, stretchHeight = true, fontStyle = FontStyle.Bold, fontSize = ScaleInteger(12), alignment = TextAnchor.MiddleRight, normal = { textColor = Color.white } }; // desc row container desc_container = new GUIStyle { stretchWidth = true, stretchHeight = true }; // entry multi-line description desc = new GUIStyle(entry_label) { fontStyle = FontStyle.Italic, alignment = TextAnchor.UpperLeft, margin = { top = 0, bottom = 0 }, padding = { top = 0, bottom = ScaleInteger(10) } }; // left icon left_icon = new GUIStyle { stretchWidth = true, stretchHeight = true, fixedWidth = ScaleFloat(16.0f), alignment = TextAnchor.MiddleLeft }; // right icon right_icon = new GUIStyle { stretchWidth = true, stretchHeight = true, margin = { left = ScaleInteger(8) }, fixedWidth = ScaleFloat(16.0f), alignment = TextAnchor.MiddleRight }; // tooltip label style tooltip = new GUIStyle(HighLogic.Skin.label) { stretchWidth = true, stretchHeight = true, fontSize = ScaleInteger(12), alignment = TextAnchor.MiddleCenter, border = new RectOffset(0, 0, 0, 0), normal = { textColor = Color.white, background = blackBackground }, margin = new RectOffset(0, 0, 0, 0), padding = new RectOffset(ScaleInteger(6), ScaleInteger(6), ScaleInteger(3), ScaleInteger(3)) }; tooltip.normal.background.wrapMode = TextureWrapMode.Repeat; // tooltip container style tooltip_container = new GUIStyle { stretchWidth = true, stretchHeight = true }; smallStationHead = new GUIStyle(HighLogic.Skin.label) { fontSize = ScaleInteger(12) }; smallStationText = new GUIStyle(HighLogic.Skin.label) { fontSize = ScaleInteger(12), normal = { textColor = Color.white } }; message = new GUIStyle() { normal = { background = blackBackground, textColor = new Color(0.66f, 0.66f, 0.66f, 1.0f) }, richText = true, stretchWidth = true, stretchHeight = true, fixedWidth = 0, fixedHeight = 0, fontSize = Styles.ScaleInteger(12), alignment = TextAnchor.MiddleCenter, border = new RectOffset(0, 0, 0, 0), padding = new RectOffset(Styles.ScaleInteger(2), Styles.ScaleInteger(2), Styles.ScaleInteger(2), Styles.ScaleInteger(2)) }; }
// return living space factor in a vessel public static double Living_space(Vessel v) { // living space is the volume per-capita normalized against an 'ideal living space' and clamped in an acceptable range return(Lib.Clamp(Volume_per_crew(v) / PreferencesComfort.Instance.livingSpace, 0.1, 1.0)); }
// add a message related to vessel resources public static void Post(Severity severity, VesselEvent e, Vessel v) { bool is_eva = v.isEVA; bool is_probe = Lib.CrewCapacity(v) == 0; string text = ""; string subtext = ""; // vessel if (!v.isEVA) { switch(e) { // electric charge case VesselEvent.ec: // manned vessel if (Lib.CrewCapacity(v) > 0) { switch(severity) { case Severity.relax: text = "$VESSEL batteries recharged"; subtext = "The crew is allowed music again"; break; case Severity.warning: text = "On $VESSEL, batteries are almost empty"; subtext = "We are squeezing the last bit of juice"; break; case Severity.danger: text = "There is no more electric charge on $VESSEL"; subtext = "Life support systems are off"; break; } } // probe else { switch(severity) { case Severity.relax: text = "$VESSEL batteries recharged"; subtext = "Systems are back online"; break; case Severity.warning: text = "On $VESSEL, batteries are almost empty"; subtext = "Shutting down non-essential systems"; break; case Severity.danger: text = "There is no more electric charge on $VESSEL"; subtext = "We lost control"; break; } } break; // food case VesselEvent.food: switch(severity) { case Severity.relax: text = "$VESSEL food reserves restored"; subtext = "Double snack rations for everybody"; break; case Severity.warning: text = "On $VESSEL, food reserves are getting low"; subtext = "Anything edible is being scrutinized"; break; case Severity.danger: text = "There is no more food on $VESSEL"; subtext = "The crew prepare to the inevitable"; break; } break; // oxygen case VesselEvent.oxygen: switch(severity) { case Severity.relax: text = "$VESSEL oxygen reserves restored"; subtext = "The crew is taking a breather"; break; case Severity.warning: text = "On $VESSEL, oxygen reserves are dangerously low"; subtext = "There is mildly panic among the crew"; break; case Severity.danger: text = "There is no more oxygen on $VESSEL"; subtext = "Everybody stop breathing"; break; } break; } } // eva else { switch(e) { // electric charge case VesselEvent.ec: switch(severity) { case Severity.relax: text = "$VESSEL recharged the battery"; break; case Severity.warning: text = "$VESSEL is running out of power"; break; case Severity.danger: text = "$VESSEL is out of power"; break; } break; // oxygen case VesselEvent.oxygen: switch(severity) { case Severity.relax: text = "$VESSEL oxygen tank has been refilled"; break; case Severity.warning: text = "$VESSEL is running out of oxygen"; break; case Severity.danger: text = "$VESSEL is out of oxygen"; break; } break; } } text = text.Replace("$VESSEL", "<color=ffffff>" + v.vesselName + "</color>"); Post(severity, text, subtext); }
// return a verbose description of shielding capability public static string Shielding_to_string(double v) { return(v <= double.Epsilon ? Local.Habitat_none : Lib.BuildString((20.0 * v / PreferencesRadiation.Instance.shieldingEfficiency).ToString("F2"), " mm"));//"none" }
// pseudo-ctor public override void OnStart(StartState state) { // don't break tutorial scenarios if (Lib.DisableScenario(this)) { return; } // check if has Connected Living Space mod hasCLS = Lib.HasAssembly("ConnectedLivingSpace"); // if part has Gravity Ring, find it. gravityRing = part.FindModuleImplementing <GravityRing>(); hasGravityRing = gravityRing != null; if (volume <= 0.0 || surface <= 0.0) { Habitat prefab = part.partInfo.partPrefab.FindModuleImplementing <Habitat>(); if (volume <= 0.0) { volume = prefab.volume; } if (surface <= 0.0) { surface = prefab.surface; } } // set RMB UI status strings Volume = Lib.HumanReadableVolume(volume); Surface = Lib.HumanReadableSurface(surface); // hide toggle if specified Events["Toggle"].active = toggle; //Actions["Action"].active = toggle; #if DEBUG Events["LogVolumeAndSurface"].active = true; #else Events["LogVolumeAndSurface"].active = Settings.VolumeAndSurfaceLogging; #endif // create animators if (!hasGravityRing) { inflate_anim = new Animator(part, inflate); } // configure on start Configure(); perctDeployed = Lib.Level(part, "Atmosphere", true); switch (this.state) { case State.enabled: Set_flow(true); break; case State.disabled: Set_flow(false); break; case State.pressurizing: Set_flow(true); break; case State.depressurizing: Set_flow(false); break; } if (Get_inflate_string().Length == 0) // not inflatable { SetPassable(true); UpdateIVA(true); } else { SetPassable(Math.Truncate(Math.Abs((perctDeployed + ResourceBalance.precision) - 1.0) * 100000) / 100000 <= ResourceBalance.precision); UpdateIVA(Math.Truncate(Math.Abs((perctDeployed + ResourceBalance.precision) - 1.0) * 100000) / 100000 <= ResourceBalance.precision); } if (Lib.IsFlight()) { // For fix IVA when crewTransfered occur, add event to define flag for FixedUpdate GameEvents.onCrewTransferred.Add(UpdateCrew); } }
public static bool IsScanning(PartModule scanner) { return(Lib.ReflectionValue <bool>(scanner, "scanning")); }
void Set_flow(bool b) { Lib.SetResourceFlow(part, "Atmosphere", b); Lib.SetResourceFlow(part, "WasteAtmosphere", b); Lib.SetResourceFlow(part, "Shielding", b); }
public void Render() { // headers foreach (Header h in headers) { GUILayout.BeginHorizontal(Styles.entry_container); if (h.leftIcon != null) { GUILayout.Label(new GUIContent(h.leftIcon.texture, h.leftIcon.tooltip), Styles.left_icon); if (h.leftIcon.click != null && Lib.IsClicked()) { callbacks.Add(h.leftIcon.click); } } GUILayout.Label(new GUIContent(h.label, h.tooltip), Styles.entry_label_nowrap); if (h.click != null && Lib.IsClicked()) { callbacks.Add(h.click); } foreach (Icon i in h.icons) { GUILayout.Label(new GUIContent(i.texture, i.tooltip), Styles.right_icon); if (i.click != null && Lib.IsClicked()) { callbacks.Add(i.click); } } GUILayout.EndHorizontal(); GUILayout.Space(Styles.ScaleFloat(10.0f)); } // sections foreach (Section p in sections) { // section title GUILayout.BeginHorizontal(Styles.section_container); if (p.left != null) { GUILayout.Label(Textures.left_arrow, Styles.left_icon); if (Lib.IsClicked()) { callbacks.Add(p.left); } } GUILayout.Label(p.title, Styles.section_text); if (p.right != null) { GUILayout.Label(Textures.right_arrow, Styles.right_icon); if (Lib.IsClicked()) { callbacks.Add(p.right); } } GUILayout.EndHorizontal(); // description if (p.desc.Length > 0) { GUILayout.BeginHorizontal(Styles.desc_container); GUILayout.Label(p.desc, Styles.desc); GUILayout.EndHorizontal(); } // entries if (p.needsSort) { p.needsSort = false; p.entries.Sort((a, b) => string.Compare(a.label, b.label, StringComparison.Ordinal)); } foreach (Entry e in p.entries) { GUILayout.BeginHorizontal(Styles.entry_container); if (e.leftIcon != null) { GUILayout.Label(new GUIContent(e.leftIcon.texture, e.leftIcon.tooltip), Styles.left_icon); if (e.leftIcon.click != null && Lib.IsClicked()) { callbacks.Add(e.leftIcon.click); } } GUILayout.Label(new GUIContent(e.label, e.tooltip), Styles.entry_label, GUILayout.Height(Styles.entry_label.fontSize)); if (e.hover != null && Lib.IsHover()) { callbacks.Add(e.hover); } GUILayout.Label(new GUIContent(e.value, e.tooltip), Styles.entry_value, GUILayout.Height(Styles.entry_value.fontSize)); if (e.click != null && Lib.IsClicked()) { callbacks.Add(e.click); } if (e.hover != null && Lib.IsHover()) { callbacks.Add(e.hover); } foreach (Icon i in e.icons) { GUILayout.Label(new GUIContent(i.texture, i.tooltip), Styles.right_icon); if (i.click != null && Lib.IsClicked()) { callbacks.Add(i.click); } } GUILayout.EndHorizontal(); } // spacing GUILayout.Space(Styles.ScaleFloat(10.0f)); } // call callbacks if (Event.current.type == EventType.Repaint) { foreach (Action func in callbacks) { func(); } callbacks.Clear(); } }
public void Update() { // The first time an existing save game is loaded with Kerbalism installed, // MM will to any existing vessels add Nitrogen with the correct capacities as set in default.cfg but they will have zero amounts, // this is not the case for any newly created vessels in the editor. if (configured) { if (state == State.enabled && Features.Pressure) { Lib.FillResource(part, "Nitrogen"); } else { Lib.EmptyResource(part, "Nitrogen"); } configured = false; } // update ui string status_str = string.Empty; switch (state) { case State.enabled: if (Math.Truncate(Math.Abs((perctDeployed + ResourceBalance.precision) - 1.0) * 100000) / 100000 > ResourceBalance.precision) { // No inflatable can be enabled been pressurizing status_str = Local.Habitat_pressurizing; } else { status_str = Local.Generic_ENABLED; } Set_pressurized(true); // GOT 12-2020 : Disabling ability to disable habs due to pressurization bugs that I'm not willing to investigate Events["Toggle"].guiActive = false; break; case State.disabled: status_str = Local.Generic_DISABLED; Set_pressurized(false); break; case State.pressurizing: status_str = Get_inflate_string().Length == 0 ? Local.Habitat_pressurizing : Local.Habitat_inflating; status_str += string.Format("{0:p2}", perctDeployed); Set_pressurized(false); break; case State.depressurizing: status_str = Get_inflate_string().Length == 0 ? Local.Habitat_depressurizing : Local.Habitat_deflating; status_str += string.Format("{0:p2}", perctDeployed); Set_pressurized(false); break; } Events["Toggle"].guiName = Lib.StatusToggle(Local.StatuToggle_Habitat, status_str);//"Habitat" // Changing this animation when we expect rotation will not work because // Unity disables other animations when playing the inflation animation. if (prev_state != State.enabled) { Set_inflation(); } prev_state = state; }
// do the particle-fitting in another thread public static void Preprocess() { // deduce number of particles int inner_count = 150000; int outer_count = 600000; int pause_count = 250000; if (Settings.LowQualityRendering) { inner_count /= 5; outer_count /= 5; pause_count /= 5; } // start time UInt64 time = Lib.Clocks(); // create all magnetic fields and do particle-fitting List <string> done = new List <string>(); foreach (var pair in models) { // get radiation data RadiationModel mf = pair.Value; // skip if model is already done if (done.Contains(mf.name)) { continue; } // add to the skip list done.Add(mf.name); // if it has a field if (mf.Has_field()) { // some feedback in the log // note: can't use BuildString here, as it is not thread-safe Lib.Log("particle-fitting '" + mf.name + "'..."); } // particle-fitting for the inner radiation belt if (mf.has_inner) { mf.inner_pmesh = new ParticleMesh(mf.Inner_func, mf.Inner_domain(), mf.Inner_offset(), inner_count, mf.inner_quality); } // particle-fitting for the outer radiation belt if (mf.has_outer) { mf.outer_pmesh = new ParticleMesh(mf.Outer_func, mf.Outer_domain(), mf.Outer_offset(), outer_count, mf.outer_quality); } // particle-fitting for the magnetopause if (mf.has_pause) { mf.pause_pmesh = new ParticleMesh(mf.Pause_func, mf.Pause_domain(), mf.Pause_offset(), pause_count, mf.pause_quality); } } // measure time required // note: can't use BuildString here, as it is not thread-safe Lib.Log("particle-fitting completed in " + Lib.Seconds(Lib.Clocks() - time).ToString("F3") + " seconds"); }
public void FixedUpdate() { // if part is manned (even in the editor), force enabled if (Lib.IsCrewed(part) && state != State.enabled) { Set_flow(true); state = State.pressurizing; // Equalize run only in Flight mode needEqualize = Lib.IsFlight(); } perctDeployed = Lib.Level(part, "Atmosphere", true); // Only handle crewTransferred & Toggle, this way has less calls in FixedUpdate // CrewTransferred Event occur after FixedUpdate, this must be check in crewtransferred if (FixIVA) { if (Get_inflate_string().Length == 0) // it is not inflatable (We always going to show and cross those habitats) { SetPassable(true); UpdateIVA(true); } else { // Inflatable modules shows IVA and are passable only in 99.9999% deployed SetPassable(Lib.IsCrewed(part) || Math.Truncate(Math.Abs((perctDeployed + ResourceBalance.precision) - 1.0) * 100000) / 100000 <= ResourceBalance.precision); UpdateIVA(Math.Truncate(Math.Abs((perctDeployed + ResourceBalance.precision) - 1.0) * 100000) / 100000 <= ResourceBalance.precision); } FixIVA = false; } // state machine switch (state) { case State.enabled: // In case it is losting pressure if (perctDeployed < Settings.PressureThreshold) { if (Get_inflate_string().Length != 0) // it is inflatable { SetPassable(false || Lib.IsCrewed(part)); // Prevent to not lock a Kerbal into a the part UpdateIVA(false); } needEqualize = true; state = State.pressurizing; } break; case State.disabled: break; case State.pressurizing: state = Pressurizing(); break; case State.depressurizing: // Just do Venting when has no gravityRing or when the gravity ring is not spinning. if (hasGravityRing && !gravityRing.Is_rotating()) { state = Depressurizing(); } else if (!hasGravityRing) { state = Depressurizing(); } break; } }
// 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 += Settings.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 += Settings.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); }
// volume / surface evaluation at prefab compilation public override void OnLoad(ConfigNode node) { // volume/surface calcs are quite slow and memory intensive, so we do them only once on the prefab // then get the prefab values from OnStart. Moreover, we cache the results in the // Kerbalism\HabitatData.cache file and reuse those cached results on next game launch. if (HighLogic.LoadedScene == GameScenes.LOADING) { if (volume <= 0.0 || surface <= 0.0) { if (habitatDatabase == null) { ConfigNode dbRootNode = ConfigNode.Load(HabitatDataCachePath); ConfigNode[] habInfoNodes = dbRootNode?.GetNodes(habitatDataCacheNodeName); habitatDatabase = new Dictionary <string, Lib.PartVolumeAndSurfaceInfo>(); if (habInfoNodes != null) { for (int i = 0; i < habInfoNodes.Length; i++) { string partName = habInfoNodes[i].GetValue("partName") ?? string.Empty; if (!string.IsNullOrEmpty(partName) && !habitatDatabase.ContainsKey(partName)) { habitatDatabase.Add(partName, new Lib.PartVolumeAndSurfaceInfo(habInfoNodes[i])); } } } } // SSTU specific support copypasted from the old system, not sure how well this works foreach (PartModule pm in part.Modules) { if (pm.moduleName == "SSTUModularPart") { Bounds bb = Lib.ReflectionCall <Bounds>(pm, "getModuleBounds", new Type[] { typeof(string) }, new string[] { "CORE" }); if (bb != null) { if (volume <= 0.0) { volume = Lib.BoundsVolume(bb) * 0.785398; // assume it's a cylinder } if (surface <= 0.0) { surface = Lib.BoundsSurface(bb) * 0.95493; // assume it's a cylinder } } return; } } string configPartName = part.name.Replace('.', '_'); Lib.PartVolumeAndSurfaceInfo partInfo; if (!habitatDatabase.TryGetValue(configPartName, out partInfo)) { // Find deploy/retract animations, either here on in the gravityring module // then set the part to the deployed state before doing the volume/surface calcs // if part has Gravity Ring, find it. gravityRing = part.FindModuleImplementing <GravityRing>(); hasGravityRing = gravityRing != null; // create animators and set the model to the deployed state if (hasGravityRing) { gravityRing.deploy_anim = new Animator(part, gravityRing.deploy); gravityRing.deploy_anim.reversed = gravityRing.animBackwards; if (gravityRing.deploy_anim.IsDefined) { gravityRing.deploy_anim.Still(1.0); } } else { inflate_anim = new Animator(part, inflate); inflate_anim.reversed = animBackwards; if (inflate_anim.IsDefined) { inflate_anim.Still(1.0); } } // get surface and volume partInfo = Lib.GetPartVolumeAndSurface(part, Settings.VolumeAndSurfaceLogging); habitatDatabase.Add(configPartName, partInfo); } partInfo.GetUsingMethod( volumeAndSurfaceMethod != Lib.VolumeAndSurfaceMethod.Best ? volumeAndSurfaceMethod : partInfo.bestMethod, out double infoVolume, out double infoSurface, substractAttachementNodesSurface); if (volume <= 0.0) { volume = infoVolume; } if (surface <= 0.0) { surface = infoSurface; } } } }
public static void NetMan(this Panel p, Vessel v) { // avoid corner-case when this is called in a lambda after scene changes v = FlightGlobals.FindVessel(v.id); // if vessel doesn't exist anymore, leave the panel empty if (v == null) { return; } // get info from the cache Vessel_Info vi = Cache.VesselInfo(v); // if not a valid vessel, leave the panel empty if (!vi.is_valid) { return; } // set metadata p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, 20), " <color=#cccccc>NETWORK INFO</color>")); // time-out simulation #if !DEBUG if (p.Timeout(vi)) { return; } #endif p.SetSection("ADAPTORS"); p.Set_IsFreqSelector(true); // store all devices var devices = new Dictionary <uint, NetDevice>(); // store device being added NetDevice adap; // loaded vessel if (v.loaded) { foreach (NetworkAdaptor m in Lib.FindModules <NetworkAdaptor>(v)) { adap = new NetAdaptorDevice(m); // add the device // - multiple same-type components in the same part will have the same id, and are ignored if (!devices.ContainsKey(adap.Id())) { devices.Add(adap.Id(), adap); } } } else { // store data required to support multiple modules of same type in a part var PD = new Dictionary <string, Lib.module_prefab_data>(); // for each part foreach (ProtoPartSnapshot proto in v.protoVessel.protoPartSnapshots) { // get part prefab (required for module properties) Part part_prefab = PartLoader.getPartInfoByName(proto.partName).partPrefab; // get all module prefabs var module_prefabs = part_prefab.FindModulesImplementing <PartModule>(); // clear module indexes PD.Clear(); // for each module foreach (ProtoPartModuleSnapshot m in proto.modules) { // get the module prefab // if the prefab doesn't contain this module, skip it PartModule module_prefab = Lib.ModulePrefab(module_prefabs, m.moduleName, PD); if (!module_prefab) { continue; } // if the module is disabled, skip it // note: this must be done after ModulePrefab is called, so that indexes are right if (!Lib.Proto.GetBool(m, "isEnabled")) { continue; } if (m.moduleName == "NetworkAdaptor") { adap = new ProtoNetAdaptorDevice(m, proto.flightID, v); // add the device // - multiple same-type components in the same part will have the same id, and are ignored if (!devices.ContainsKey(adap.Id())) { devices.Add(adap.Id(), adap); } } } } } // dict order by device name // for each device foreach (var pair in devices.OrderBy(x => x.Value.Name())) { // render device entry NetDevice dev = pair.Value; // Get how many antennas share the same freq AntennasByFrequency x = null; if (vi.antenna.antennasByFreq.ContainsKey(dev.InfoFreq())) { x = vi.antenna.antennasByFreq[dev.InfoFreq()]; } p.SetContent(dev.Name(), dev.InfoRate(), string.Empty, null, () => Highlighter.Set(dev.Part(), Color.cyan), dev.InfoFreq()); p.SetIcon(Icons.left_freq, "Decrease", () => { if (dev.InfoFreq() > 0) // && x != null { //if (x.antCount == 1 && x.countConnections > 0) //{ // Lib.Popup( // "Warning!", // Lib.BuildString("This is the last antenna on '", dev.InfoFreq().ToString(), // "' frequency.\nYou will lost connection in this frequency.\nDo you really want to remove this frequency from this vessel?"), // new DialogGUIButton("Remove", () => dev.ChangeFreq(-1)), // new DialogGUIButton("Keep it", () => { })); //} //else dev.ChangeFreq(-1); } }); p.SetIcon(Icons.right_freq, "Increase", () => { if (dev.InfoFreq() < 99) // && x != null { //if (x.antCount == 1 && x.countConnections > 0) //{ // Lib.Popup( // "Warning!", // Lib.BuildString("This is the last antenna on '", dev.InfoFreq().ToString(), // "' frequency.\nYou will lost connection in this frequency.\nDo you really want to remove this frequency from this vessel?"), // new DialogGUIButton("Remove", () => dev.ChangeFreq(+1)), // new DialogGUIButton("Keep it", () => { })); //} //else dev.ChangeFreq(+1); } }); } p.SetSection("FREQUENCY(S) DETAIL"); foreach (short key in vi.antenna.antennasByFreq.Keys) { double range = vi.antenna.antennasByFreq[key].antennaPower; double rate = vi.antenna.antennasByFreq[key].antennaRate; Render_ConnectionDetail(p, range, rate, key); } }
public void FixedUpdate() { // do nothing in the editor if (Lib.IsEditor()) { return; } // if it has not malfunctioned if (!broken) { // calculate time of next failure if necessary if (next <= double.Epsilon) { last = Planetarium.GetUniversalTime(); next = last + mtbf * (quality ? Settings.QualityScale : 1.0) * 2.0 * Lib.RandomDouble(); } // if it has failed, trigger malfunction if (Planetarium.GetUniversalTime() > next) { Break(); } } }