Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 108 additions & 18 deletions Telecom/connection_availability.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ContractConfigurator;
using ContractConfigurator.Parameters;
using Contracts;
using RealAntennas;

Expand Down Expand Up @@ -46,7 +48,7 @@ public override ConnectionAvailability.Goal Goal() {
}
}

public class BroadcastRxAvailability : ContractParameter {
public class BroadcastRxAvailability : ContractConfiguratorParameter {
public BroadcastRxAvailability(Service service,
AvailabilityMetric metric,
Monitor monitor,
Expand All @@ -72,20 +74,20 @@ protected override void OnUpdate() {
return;
}
if (metric_.partial) {
SetIncomplete();
SetState(ParameterState.Incomplete);
} else if (metric_.availability < availability_) {
if (goal_ == ConnectionAvailability.Goal.MAINTAIN) {
SetFailed();
SetState(ParameterState.Failed);
} else {
SetIncomplete();
SetState(ParameterState.Incomplete);
}
} else {
SetComplete();
SetState(ParameterState.Complete);
}
GetTitle();
}

protected override string GetTitle() {
protected override string GetParameterTitle() {
string status = service_.available
? "Currently connected"
: "Currently disconnected";
Expand All @@ -100,6 +102,9 @@ protected override string GetTitle() {
return title;
}

protected override void OnParameterLoad(ConfigNode node) { }
protected override void OnParameterSave(ConfigNode node) { }

private Service service_;
private AvailabilityMetric metric_;
private Monitor monitor_;
Expand All @@ -110,7 +115,7 @@ protected override string GetTitle() {
private TitleTracker title_tracker_;
}

public class ConnectionAvailability : ContractParameter {
public class ConnectionAvailability : ContractConfiguratorParameter {
public enum Goal {
ACHIEVE,
MAINTAIN,
Expand All @@ -136,6 +141,19 @@ public ConnectionAvailability(string connection,
monitoring_definition_ = monitoring_definition;
}

private static string ForceGetStationName(string name) {
// Gets the station's readable name, even if it isn't in the network yet. **Can be very slow!!**
// Attempt, in order:
// - Get from the active Network
// - Read from config
if (Telecom.Instance.network.GetStation(name) is RealAntennas.Network.RACommNetHome home) {
return home.displaynodeName;
} else {
return Network.GetStationDefinition(name).GetValue("objectName");
// This was pretty bad before caching Station definitions.
}
}

protected override void OnUpdate() {
base.OnUpdate();
if (goal_ == Goal.MAINTAIN) {
Expand All @@ -149,32 +167,32 @@ protected override void OnUpdate() {
any_incomplete |= subparameter.State == ParameterState.Incomplete;
}
if (any_failed) {
SetFailed();
SetState(ParameterState.Failed);
} else if (any_incomplete) {
SetIncomplete();
SetState(ParameterState.Incomplete);
} else {
SetComplete();
SetState(ParameterState.Complete);
}
} else {
if (state == ParameterState.Failed) {
return;
}
if (metric.partial) {
SetIncomplete();
SetState(ParameterState.Incomplete);
} else if (metric.availability < availability_) {
if (goal_ == Goal.MAINTAIN) {
SetFailed();
SetState(ParameterState.Failed);
} else {
SetIncomplete();
SetState(ParameterState.Incomplete);
}
} else {
SetComplete();
SetState(ParameterState.Complete);
}
}
GetTitle();
GetParameterTitle();
}

protected override void OnLoad(ConfigNode node) {
protected override void OnParameterLoad(ConfigNode node) {
connection_ = node.GetValue("connection");
availability_ = double.Parse(node.GetValue("availability"));
latency_ = node.HasValue("latency")
Expand All @@ -189,9 +207,11 @@ protected override void OnLoad(ConfigNode node) {
}
metric_definition_ = node.GetNode("metric");
monitoring_definition_ = node.GetNode("monitoring");
preview_string_ = node.HasValue("preview")
? node.GetValue("preview") : null;
}

protected override void OnSave(ConfigNode node) {
protected override void OnParameterSave(ConfigNode node) {
node.AddValue("connection", connection_);
node.AddValue("availability", availability_);
if (latency_ != null) {
Expand All @@ -200,9 +220,10 @@ protected override void OnSave(ConfigNode node) {
node.AddValue("goal", goal_);
node.AddNode("metric", metric_definition_);
node.AddNode("monitoring", monitoring_definition_);
node.AddValue("preview", preview_string);
}

protected override string GetTitle() {
protected override string GetParameterTitle() {
var connection = Telecom.Instance.network.GetConnection(connection_);
string data_rate = RATools.PrettyPrintDataRate(connection.data_rate);
double latency = latency_ ?? connection.latency_limit;
Expand Down Expand Up @@ -256,6 +277,11 @@ protected override string GetTitle() {
return title;
}

protected override string GetParameterTitlePreview(out bool hideChildren) {
hideChildren = false;
return preview_string;
}

private AvailabilityMetric MakeMetric(ConfigNode definition) {
string type = definition.GetValue("type");
if (type == "monthly") {
Expand Down Expand Up @@ -403,6 +429,69 @@ private List<BroadcastRxAvailability> subparameters {
}
}

private string preview_string {
get {
if (!(preview_string_ is null)) {
return preview_string_;
}
//if (goal_ == Goal.MAINTAIN) {
// return null; // Don't bother generating for maintenance contracts
//}

// We need a couple things to preview the connection, and they should ideally never change.

double data_rate;
double latency;
string tx = null;
string[] rxs = null;
string[] trxs = null;

if (Telecom.Instance.network.GetConnectionSafe(connection_) is Connection connection) {
// The sane option.
data_rate = connection.data_rate;
latency = connection.latency_limit;
if (connection is PointToMultipointConnection point_to_multipoint) {
tx = point_to_multipoint.tx_name;
rxs = point_to_multipoint.rx_names;
} else if (connection is DuplexConnection duplex) {
trxs = duplex.trx_names;
}
} else {
// The stupid option.
ConfigNode conn = Network.GetConnectionDefinition(connection_);
data_rate = double.Parse(conn.GetValue("rate"));
latency = latency_ ?? double.Parse(conn.GetValue("latency"));
if (conn.HasValue("tx")) {
tx = conn.GetValue("tx");
rxs = conn.GetValues("rx");
} else {
trxs = conn.GetValues("trx");
}
}
string pretty_rate = RATools.PrettyPrintDataRate(data_rate);
string pretty_latency = latency >= 1 ? $"{latency} s" : $"{latency * 1000} ms";

if (!(tx is null)) {
if (rxs.Length > 1) {
return $"Support broadcast from {ForceGetStationName(tx)} to " +
$"{string.Join(", ", rxs.Take(rxs.Length - 1).Select(rx => ForceGetStationName(rx)))}" +
$" and {ForceGetStationName(rxs[rxs.Length - 1])}, with a data rate of {pretty_rate} and a " +
$"latency of at most {pretty_latency}. Target availability: {availability_:P2}";
// Don't add subparameters just for preview purposes, we'll just list them out instead.
} else {
return $"Support transmission from {ForceGetStationName(tx)} to " +
$"{ForceGetStationName(rxs[0])}, with a data rate of {pretty_rate} and a " +
$"latency of at most {pretty_latency}. Target availability: {availability_:P2}";
}
} else {
return $"Support duplex communication between {ForceGetStationName(trxs[0])} " +
$"and {ForceGetStationName(trxs[1])}, with a one-way data rate of " +
$"{pretty_rate} and a round-trip latency of at most " +
$"{pretty_latency}. Target availability: {availability_:P2}";
}
}
}

public string connection_name => connection_;

private List<BroadcastRxAvailability> subparameters_;
Expand All @@ -416,5 +505,6 @@ private List<BroadcastRxAvailability> subparameters {
private Goal goal_;
private string last_title_;
private TitleTracker title_tracker_;
private string preview_string_;
}
}
40 changes: 33 additions & 7 deletions Telecom/network.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,34 @@

namespace σκοπός {
public class Network {
static ConfigNode GetStationDefinition(string name) {
public static ConfigNode GetStationDefinition(string name) {
if (station_definition_cache_.ContainsKey(name)) {
return station_definition_cache_[name];
} else {
foreach (var block in GameDatabase.Instance.GetConfigs("skopos_telecom")) {
foreach (var definition in block.config.GetNodes("station")) {
if (definition.GetValue("name") == name) {
return definition;
var station_name = definition.GetValue("name");
station_definition_cache_[station_name] = definition;
if (station_name == name) {
return definition;
}
}
}
}
throw new KeyNotFoundException($"No definition for station {name}");
}

static ConfigNode GetConnectionDefinition(string name) {
public static ConfigNode GetConnectionDefinition(string name) {
if (connection_definition_cache_.ContainsKey(name)) {
return connection_definition_cache_[name];
} else {
foreach (var block in GameDatabase.Instance.GetConfigs("skopos_telecom")) {
foreach (var definition in block.config.GetNodes("connection")) {
if (definition.GetValue("name") == name) {
return definition;
var connection_name = definition.GetValue("name");
connection_definition_cache_[connection_name] = definition;
if (connection_name == name) {
return definition;
}
}
}
}
Expand Down Expand Up @@ -226,8 +238,18 @@ public Connection GetConnection(string name) {
}
}

public Connection GetConnectionSafe(string name) {
if (!connections_.TryGetValue(name, out var connection)) {
return null;
}
return connection;
}

public RACommNetHome GetStation(string name) {
return stations_[name];
if (!stations_.TryGetValue(name, out var station)) {
return null;
}
return station;
}

public IEnumerable<RACommNetHome> AllGround() {
Expand All @@ -246,6 +268,10 @@ public IEnumerable<RACommNetHome> AllGround() {
public string[] names_ = { };
public Routing routing_ = new Routing();

private static readonly Dictionary<string, ConfigNode> station_definition_cache_ = new Dictionary<string, ConfigNode>();
private static readonly Dictionary<string, ConfigNode> connection_definition_cache_ = new Dictionary<string, ConfigNode>();
// purposefully don't save these two, we want these to invalidate on game relaunch

public Dictionary<Contracts.Contract, List<Connection>> connections_by_contract { get; } =
new Dictionary<Contracts.Contract, List<Connection>>();
public HashSet<Connection> contracted_connections { get; } = new HashSet<Connection>();
Expand Down