diff --git a/Telecom/connection_availability.cs b/Telecom/connection_availability.cs index 1f0b99a..14600f9 100644 --- a/Telecom/connection_availability.cs +++ b/Telecom/connection_availability.cs @@ -138,6 +138,9 @@ public ConnectionAvailability(string connection, protected override void OnUpdate() { base.OnUpdate(); + if (goal_ == Goal.MAINTAIN) { + monitor?.AlertIfNeeded(); + } if (subparameters != null) { bool any_failed = false; bool any_incomplete = false; @@ -245,9 +248,6 @@ protected override string GetTitle() { $"Availability: {metric.description}\nTarget: {availability_:P2}"; } - if (goal_ == Goal.MAINTAIN) { - monitor?.AlertIfNeeded(); - } title_tracker_.Add(title); if (last_title_ != title) { title_tracker_.UpdateContractWindow(title); diff --git a/Telecom/ground_segment_mutation.cs b/Telecom/ground_segment_mutation.cs index 5b92d14..0667394 100644 --- a/Telecom/ground_segment_mutation.cs +++ b/Telecom/ground_segment_mutation.cs @@ -100,7 +100,7 @@ protected void Behave() { Telecom.Instance.network.AddStations(stations_); Telecom.Instance.network.AddConnections(connections_); } - Telecom.Instance.network.Refresh(); + Telecom.Instance.ReloadContractConnections(null); } private Operation operation_; diff --git a/Telecom/main_window.cs b/Telecom/main_window.cs index a6835c8..bc376c3 100644 --- a/Telecom/main_window.cs +++ b/Telecom/main_window.cs @@ -19,8 +19,21 @@ protected override void RenderWindowContents(int window_id) { UnityEngine.GUILayout.Label("Please wait for the Σκοπός Telecom network to initialize..."); return; } + if (string.IsNullOrEmpty(s_alert_rate_limit_)) { + s_alert_rate_limit_ = telecom_.alert_rate_limit_.ToString(); + } // MainWindow initialization is before this field was loaded by the scenario. + using (new UnityEngine.GUILayout.VerticalScope()) { - show_network = UnityEngine.GUILayout.Toggle(show_network, "Show network"); + using (new UnityEngine.GUILayout.HorizontalScope()) { + show_network = UnityEngine.GUILayout.Toggle(show_network, "Show network"); + telecom_.stop_warp_in_sim = UnityEngine.GUILayout.Toggle(telecom_.stop_warp_in_sim, "Alerts stop warp in RP-1 sim"); + } + using (new UnityEngine.GUILayout.HorizontalScope()) { + UnityEngine.GUILayout.Label("Suppress duplicate SLA alerts within"); + s_alert_rate_limit_ = UnityEngine.GUILayout.TextField(s_alert_rate_limit_); + double.TryParse(s_alert_rate_limit_, out telecom_.alert_rate_limit_); + UnityEngine.GUILayout.Label($"days ({telecom_.alert_rate_limit_})"); + } var inspected_connections = connection_inspectors_.Keys.ToArray(); foreach (var inspected_connection in inspected_connections) { if (!telecom_.network.contracted_connections.Contains(inspected_connection)) { @@ -114,6 +127,7 @@ protected override void RenderWindowContents(int window_id) { antenna_inspectors_; private Telecom telecom_; + private string s_alert_rate_limit_; private readonly Dictionary open_contracts_ = new Dictionary(); private readonly Dictionary connection_inspectors_ = diff --git a/Telecom/monitor.cs b/Telecom/monitor.cs index 4a415c3..0b3742f 100644 --- a/Telecom/monitor.cs +++ b/Telecom/monitor.cs @@ -9,39 +9,41 @@ public Monitor(string service_name, } public void AlertIfNeeded() { + var telecom = Telecom.Instance; if (metric_.availability >= availability_threshold_) { - if (alerted_) { + if (alerted_ && (telecom.last_universal_time > last_restore_time_ + telecom.alert_rate_limit_ * 86400)) { alerted_ = false; + last_restore_time_ = telecom.last_universal_time; ScreenMessages.PostScreenMessage( $@"{service_name_}: availability is back to normal", 30, ScreenMessageStyle.UPPER_CENTER, XKCDColors.Pear); KSP.UI.Screens.MessageSystem.Instance.AddMessage( new KSP.UI.Screens.MessageSystem.Message( messageTitle: $"{service_name_} is back to normal", - message: $@"The availability is {metric_.description - }, back above the target of {availability_threshold_:P2}.", + message: $@"The availability is {metric_.description}, back above the target of {availability_threshold_:P2}.", KSP.UI.Screens.MessageSystemButton.MessageButtonColor.GREEN, KSP.UI.Screens.MessageSystemButton.ButtonIcons.COMPLETE)); } } else { - if (!alerted_) { + if (!alerted_ && (telecom.last_universal_time > last_alert_time_ + telecom.alert_rate_limit_ * 86400)) { alerted_ = true; - TimeWarp.fetch.CancelAutoWarp(); - TimeWarp.SetRate( - TimeWarp.fetch.warpRates.IndexOf(1), - instant: true, - postScreenMessage: false); + last_alert_time_ = telecom.last_universal_time; + if (telecom.stop_warp_in_sim || !RP0.SpaceCenterManagement.Instance.IsSimulatedFlight) { + TimeWarp.fetch.CancelAutoWarp(); + TimeWarp.SetRate( + TimeWarp.fetch.warpRates.IndexOf(1), + instant: true, + postScreenMessage: false); + } ScreenMessages.PostScreenMessage( - $@"WARNING: {service_name_}: availability is below { - availability_threshold_:P2}.", - 30, ScreenMessageStyle.UPPER_CENTER, XKCDColors.Orange); + $@"WARNING: {service_name_}: availability is below {availability_threshold_:P2}.", + 30, ScreenMessageStyle.UPPER_CENTER, XKCDColors.Orange); KSP.UI.Screens.MessageSystem.Instance.AddMessage( - new KSP.UI.Screens.MessageSystem.Message( - messageTitle: $"Out of SLA on {service_name_}", - message: $@"The availability is {metric_.description - }, below the target of {availability_threshold_:P2}.", - KSP.UI.Screens.MessageSystemButton.MessageButtonColor.ORANGE, - KSP.UI.Screens.MessageSystemButton.ButtonIcons.ALERT)); + new KSP.UI.Screens.MessageSystem.Message( + messageTitle: $"Out of SLA on {service_name_}", + message: $@"The availability is {metric_.description}, below the target of {availability_threshold_:P2}.", + KSP.UI.Screens.MessageSystemButton.MessageButtonColor.ORANGE, + KSP.UI.Screens.MessageSystemButton.ButtonIcons.ALERT)); } } } @@ -52,5 +54,7 @@ public void AlertIfNeeded() { private AvailabilityMetric metric_; private double availability_threshold_; private bool alerted_ = false; + private double last_alert_time_ = 0; + private double last_restore_time_ = 0; } } diff --git a/Telecom/network.cs b/Telecom/network.cs index 650cfed..31d2738 100644 --- a/Telecom/network.cs +++ b/Telecom/network.cs @@ -44,7 +44,6 @@ public Network(ConfigNode network_specification) { foreach (ConfigNode node in connection_nodes) { connections_[node.GetValue("name")].Load(node); } - ReloadContractConnections(); (CommNet.CommNetScenario.Instance as RACommNetScenario).Network.InvalidateCache(); // Inform RA of changes to the node list. } @@ -92,13 +91,14 @@ RACommNetHome MakeStation(string name) { station_node.AddValue("isKSC", false); station_node.AddValue("isHome", false); station_node.AddValue("icon", "RealAntennas/radio-antenna"); + Telecom.Log($"Ground TL is {RACommNetScenario.GroundStationTechLevel}"); foreach (var antenna in node.GetNodes("Antenna")) { Telecom.Log($"antenna for {name}: {antenna}"); - Telecom.Log($"Ground TL is {RACommNetScenario.GroundStationTechLevel}"); station_node.AddNode(antenna); } station.Configure(station_node, body); if (RACommNetScenario.GroundStations.TryGetValue(station.nodeName, out RACommNetHome oldStation)) { + Telecom.Log($"Ground station {station.nodeName} was already registered in RA, deleting the old instance"); RACommNetScenario.GroundStations.Remove(station.nodeName); UnityEngine.Object.Destroy(oldStation); } diff --git a/Telecom/telecom.cs b/Telecom/telecom.cs index c27a22c..186c5f6 100644 --- a/Telecom/telecom.cs +++ b/Telecom/telecom.cs @@ -47,14 +47,20 @@ public void Start() { Log("Starting"); enabled = false; GameEvents.CommNet.OnNetworkInitialized.Add(NetworkInitializedNotify); + GameEvents.Contract.onContractsLoaded.Add(NotifyContractsLoaded); StartCoroutine(CreateNetwork()); } public void OnDestroy() { Log("Destroying"); GameEvents.CommNet.OnNetworkInitialized.Remove(NetworkInitializedNotify); - GameEvents.Contract.onAccepted.Remove(OnContractsChanged); - GameEvents.Contract.onFinished.Remove(OnContractsChanged); + GameEvents.Contract.onAccepted.Remove(ReloadContractConnections); + GameEvents.Contract.onFinished.Remove(ReloadContractConnections); + GameEvents.Contract.onContractsLoaded.Remove(NotifyContractsLoaded); + } + + private void NotifyContractsLoaded() { + Log("Received OnContractsLoaded GameEvent notification"); } private void NetworkInitializedNotify() { @@ -67,17 +73,19 @@ private IEnumerator CreateNetwork() { } Log("Creating Network"); network = new Network(serialized_network_); + ReloadContractConnections(null); enabled = true; - GameEvents.Contract.onAccepted.Add(OnContractsChanged); - GameEvents.Contract.onFinished.Add(OnContractsChanged); + GameEvents.Contract.onAccepted.Add(ReloadContractConnections); + GameEvents.Contract.onFinished.Add(ReloadContractConnections); while (network.AllGround().Any(x => x.Comm == null)) { + Log("Network creation stalling for station CommNetHomes to create..."); yield return new UnityEngine.WaitForEndOfFrame(); } network.UpdateStationVisibilityHandler(); } private bool on_contracts_changed_cr_running = false; - internal void OnContractsChanged(Contracts.Contract data) { + internal void ReloadContractConnections(Contracts.Contract data) { if (!on_contracts_changed_cr_running) { StartCoroutine(DelayedContractReload(data)); } @@ -85,7 +93,10 @@ internal void OnContractsChanged(Contracts.Contract data) { private IEnumerator DelayedContractReload(Contracts.Contract data) { on_contracts_changed_cr_running = true; - yield return new UnityEngine.WaitForEndOfFrame(); + yield return new UnityEngine.WaitForFixedUpdate(); + while (!Contracts.ContractSystem.loaded && network != null) { + yield return new UnityEngine.WaitForEndOfFrame(); + } network.ReloadContractConnections(); on_contracts_changed_cr_running = false; } @@ -204,6 +215,10 @@ link.b is RACommNode node_b && public double last_universal_time => ut_; [KSPField(isPersistant = true)] private double ut_; + [KSPField(isPersistant = true)] + internal double alert_rate_limit_ = 0; + [KSPField(isPersistant = true)] + public bool stop_warp_in_sim = true; private KSP.UI.Screens.ApplicationLauncherButton toolbar_button_; } }