Skip to content

Commit

Permalink
Connection diagnostics
Browse files Browse the repository at this point in the history
Display is toggled by clicking on the signal delay field in the Time Wrap display.
Connection is cached internally, and the last cached route is checked for quality.

Limitation: because no RT2 information is retained between scene changes, diagnostics
are only available for the active vessel, and only if the connection goes down while
the vessel is active.
  • Loading branch information
bk2w committed Feb 12, 2014
1 parent 731df1d commit e6b3a02
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 19 deletions.
2 changes: 1 addition & 1 deletion src/RemoteTech2/Modules/ModuleRTAntenna.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public virtual void SetState(bool state)
if (RTCore.Instance != null)
{
var satellite = RTCore.Instance.Network[Guid];
bool route_home = RTCore.Instance.Network[satellite].Any(r => r.Links[0].Interfaces.Contains(this) && RTCore.Instance.Network.GroundStations.ContainsKey(r.Goal.Guid));
bool route_home = RTCore.Instance.Network[satellite].Any(r => r.Links[0].Transmitters.Contains(this) && RTCore.Instance.Network.GroundStations.ContainsKey(r.Goal.Guid));
if (mTransmitter == null && route_home)
{
AddTransmitter();
Expand Down
2 changes: 1 addition & 1 deletion src/RemoteTech2/Modules/ModuleRTAntennaPassive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public virtual void SetState(bool state)
{
IsRTActive = state;
var satellite = RTCore.Instance.Network[Guid];
bool route_home = RTCore.Instance.Network[satellite].Any(r => r.Links[0].Interfaces.Contains(this) && RTCore.Instance.Network.GroundStations.ContainsKey(r.Goal.Guid));
bool route_home = RTCore.Instance.Network[satellite].Any(r => r.Links[0].Transmitters.Contains(this) && RTCore.Instance.Network.GroundStations.ContainsKey(r.Goal.Guid));
if (mTransmitter == null && route_home)
{
AddTransmitter();
Expand Down
16 changes: 16 additions & 0 deletions src/RemoteTech2/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ public partial class NetworkManager : IEnumerable<ISatellite>
}
}

private Dictionary<ISatellite, NetworkRoute<ISatellite>> mLastConnectionCache = new Dictionary<ISatellite, NetworkRoute<ISatellite>>();
public NetworkRoute<ISatellite> LastConnection(ISatellite sat) {

if (sat == null) return null;
return mLastConnectionCache.ContainsKey(sat) ? mLastConnectionCache[sat] : null;
}


private const int REFRESH_TICKS = 50;

private int mTick;
Expand Down Expand Up @@ -103,6 +111,14 @@ public void FindPath(ISatellite start, IEnumerable<ISatellite> commandStations)
}
mConnectionCache[start] = paths.Where(p => p.Exists).ToList();
mConnectionCache[start].Sort((a, b) => a.Delay.CompareTo(b.Delay));

// If theres a valid path, set it aside for diagnostics
if (mConnectionCache[start].Count > 0)
{
// Debug.Log(String.Format("Saving a connection from {0} to {1} of {2} links", start.Name, mConnectionCache[start][0].Links, mConnectionCache[start][0].Links.Count));
mLastConnectionCache[start] = mConnectionCache[start][0];
}

start.OnConnectionRefresh(this[start]);
}

Expand Down
6 changes: 2 additions & 4 deletions src/RemoteTech2/NetworkPathfinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ public static class NetworkPathfinder
var nodeMap = new Dictionary<T, Node<NetworkLink<T>>>();
var priorityQueue = new PriorityQueue<Node<NetworkLink<T>>>();

var nStart = new Node<NetworkLink<T>>(new NetworkLink<T>(start, null, LinkType.None), 0, heuristicFunction.Invoke(start, goal), null, false);
var nStart = new Node<NetworkLink<T>>(new NetworkLink<T>(start, null, null, LinkType.None, heuristicFunction.Invoke(start, goal)), 0, heuristicFunction.Invoke(start, goal), null, false);
nodeMap[start] = nStart;
priorityQueue.Enqueue(nStart);
double cost = 0;

while (priorityQueue.Count > 0)
{
Expand All @@ -32,10 +31,9 @@ public static class NetworkPathfinder
for (var node = current; node.From != null; node = node.From)
{
reversePath.Add(node.Item);
cost += node.Cost;
}
reversePath.Reverse();
return new NetworkRoute<T>(start, reversePath, cost);
return new NetworkRoute<T>(start, reversePath, current.Cost);
}

foreach (var link in neighborsFunction.Invoke(current.Item.Target))
Expand Down
6 changes: 6 additions & 0 deletions src/RemoteTech2/RangeModel/RangeModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace RemoteTech
{
Expand Down Expand Up @@ -33,6 +34,11 @@ public static bool IsTargetingPlanet(this IAntenna a, ISatellite sat_b, ISatelli
return false;
}

public static bool IsTargeting(this IAntenna a, ISatellite sat_b, ISatellite sat_a)
{
return (a.Omni > 0) || IsTargetingDirectly(a, sat_b) || IsTargetingActiveVessel(a, sat_b) || IsTargetingPlanet(a, sat_b, sat_a);
}

public static double DistanceTo(this ISatellite a, ISatellite b)
{
return Vector3d.Distance(a.Position, b.Position);
Expand Down
10 changes: 6 additions & 4 deletions src/RemoteTech2/RangeModel/RangeModelRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public static NetworkLink<ISatellite> GetLink(ISatellite sat_a, ISatellite sat_b
{
var omni_a = sat_a.Antennas.Where(a => a.Omni > 0);
var omni_b = sat_b.Antennas.Where(b => b.Omni > 0);
var dish_a = sat_a.Antennas.Where(a => a.Dish > 0 && (a.IsTargetingDirectly(sat_b) || a.IsTargetingActiveVessel(sat_b) || a.IsTargetingPlanet(sat_b, sat_a)));
var dish_b = sat_b.Antennas.Where(b => b.Dish > 0 && (b.IsTargetingDirectly(sat_a) || b.IsTargetingActiveVessel(sat_a) || b.IsTargetingPlanet(sat_a, sat_b)));
var dish_a = sat_a.Antennas.Where(a => a.Dish > 0 && a.IsTargeting(sat_b, sat_a));
var dish_b = sat_b.Antennas.Where(b => b.Dish > 0 && b.IsTargeting(sat_a, sat_b));

double max_omni_a = omni_a.Any() ? omni_a.Max(a => a.Omni) : 0.0;
double max_omni_b = omni_b.Any() ? omni_b.Max(b => b.Omni) : 0.0;
Expand Down Expand Up @@ -47,10 +47,12 @@ public static NetworkLink<ISatellite> GetLink(ISatellite sat_a, ISatellite sat_b

if (conn_a != null && conn_b != null)
{
var interfaces = omni_a.Concat(dish_a).ToList();
var transmitters = omni_a.Concat(dish_a).ToList();
var receivers = omni_b.Concat(dish_b).ToList();
var type = LinkType.Omni;
var cost = RTSettings.Instance.EnableSignalDelay ? distance / RTSettings.Instance.SpeedOfLight : 0.0;
if (dish_a.Contains(conn_a) || dish_b.Contains(conn_b)) type = LinkType.Dish;
return new NetworkLink<ISatellite>(sat_b, interfaces, type);
return new NetworkLink<ISatellite>(sat_b, transmitters, receivers, type, cost);
}

return null;
Expand Down
10 changes: 6 additions & 4 deletions src/RemoteTech2/RangeModel/RangeModelStandard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public static NetworkLink<ISatellite> GetLink(ISatellite sat_a, ISatellite sat_b
double distance = sat_a.DistanceTo(sat_b);
var omni_a = sat_a.Antennas.Where(a => a.Omni > 0);
var omni_b = sat_b.Antennas.Where(b => b.Omni > 0);
var dish_a = sat_a.Antennas.Where(a => a.Dish > distance && (a.IsTargetingDirectly(sat_b) || a.IsTargetingActiveVessel(sat_b) || a.IsTargetingPlanet(sat_b, sat_a)));
var dish_b = sat_b.Antennas.Where(b => b.Dish > distance && (b.IsTargetingDirectly(sat_a) || b.IsTargetingActiveVessel(sat_a) || b.IsTargetingPlanet(sat_a, sat_b)));
var dish_a = sat_a.Antennas.Where(a => a.Dish > distance && a.IsTargeting(sat_b, sat_a));
var dish_b = sat_b.Antennas.Where(b => b.Dish > distance && b.IsTargeting(sat_a, sat_b));

double bonus_a = 0;
double bonus_b = 0;
Expand All @@ -37,10 +37,12 @@ public static NetworkLink<ISatellite> GetLink(ISatellite sat_a, ISatellite sat_b

if (conn_a != null && conn_b != null)
{
var interfaces = omni_a.Concat(dish_a).ToList();
var transmitters = omni_a.Concat(dish_a).ToList();
var receivers = omni_b.Concat(dish_b).ToList();
var type = LinkType.Omni;
var cost = RTSettings.Instance.EnableSignalDelay ? distance / RTSettings.Instance.SpeedOfLight : 0.0;
if (dish_a.Contains(conn_a) || dish_b.Contains(conn_b)) type = LinkType.Dish;
return new NetworkLink<ISatellite>(sat_b, interfaces, type);
return new NetworkLink<ISatellite>(sat_b, transmitters, receivers, type, cost);
}

return null;
Expand Down
12 changes: 8 additions & 4 deletions src/RemoteTech2/SimpleTypes/NetworkLink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ namespace RemoteTech
public class NetworkLink<T> : IEquatable<NetworkLink<T>>
{
public readonly T Target;
public readonly List<IAntenna> Interfaces;
public readonly List<IAntenna> Transmitters;
public readonly List<IAntenna> Receivers;
public readonly LinkType Port;
public double Cost { get; set;}

public NetworkLink(T sat, List<IAntenna> ant, LinkType port)
public NetworkLink(T sat, List<IAntenna> tx_ant, List<IAntenna> rx_ant, LinkType port, double cost)
{
Target = sat;
Interfaces = ant;
Transmitters = tx_ant;
Receivers = rx_ant;
Port = port;
Cost = cost;
}

public bool Equals(NetworkLink<T> o)
Expand All @@ -25,7 +29,7 @@ public bool Equals(NetworkLink<T> o)

public override string ToString()
{
return String.Format("NetworkLink(T: {0}, I: {1}, P: {2})", Target, Interfaces.ToDebugString(), Port);
return String.Format("NetworkLink(T: {0}, TX: {1}, RX: {2} P: {3}, C: {4})", Target, Transmitters.ToDebugString(), Receivers.ToDebugString(), Port, Cost);
}
}
}
126 changes: 125 additions & 1 deletion src/RemoteTech2/UI/TimeQuadrantPatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ private GUIStyle ButtonStyle

private Backup mBackup;
private GUIStyle mTextStyle;
private GUIStyle mGreenTextStyle;
private GUIStyle mRedTextStyle;
private GUIStyle mTargetTextStyle;
private bool mDisplayRoute;

static TimeQuadrantPatcher()
{
Expand Down Expand Up @@ -157,6 +161,21 @@ public void Patch()
mTextStyle = new GUIStyle(text.textStyle);
mTextStyle.fontSize = (int)(text.textSize * ScreenSafeUI.PixelRatio);

mGreenTextStyle = new GUIStyle(mTextStyle);
mGreenTextStyle.normal.textColor = Color.green;
mGreenTextStyle.alignment = TextAnchor.LowerRight;

mRedTextStyle = new GUIStyle(mTextStyle);
mRedTextStyle.normal.textColor = Color.red;
mRedTextStyle.alignment = TextAnchor.LowerRight;

mTargetTextStyle = new GUIStyle(mTextStyle);
mTargetTextStyle.normal.textColor = Color.green;
mTargetTextStyle.alignment = TextAnchor.LowerLeft;


mDisplayRoute = false;

RenderingManager.AddToPostDrawQueue(0, Draw);
}

Expand Down Expand Up @@ -204,6 +223,105 @@ public void Undo()
catch (Exception) { }
}

private void DrawSignalRoute()
{
float scale = ScreenSafeUI.VerticalRatio * 900.0f / Screen.height;
Vector2 screenCoord = ScreenSafeUI.referenceCam.WorldToScreenPoint(mBackup.TimeQuadrant.timeQuadrantTab.transform.position);

float distanceWidth = 80;
float antennaWidth = 40;
float targetWidth = 250;
float areaWidth = distanceWidth + antennaWidth + antennaWidth + targetWidth;
float lineHeight = 20;

var satellite = RTCore.Instance.Satellites[FlightGlobals.ActiveVessel];
var source = satellite as ISatellite;
NetworkRoute<ISatellite> connection;

// If there are no connections, or an infinite delay connection, examine the LastConnection
// other wise use the currently shortest connection
if (RTCore.Instance.Network[satellite].Count == 0 ||
Double.IsPositiveInfinity(RTCore.Instance.Network[satellite][0].Delay))
connection = RTCore.Instance.Network.LastConnection(satellite);
else
connection = RTCore.Instance.Network[satellite][0];

if(connection == null)
GUILayout.BeginArea(new Rect(5.0f / scale, Screen.height - screenCoord.y + 38.0f / scale, areaWidth, lineHeight * 2));
else
GUILayout.BeginArea(new Rect(5.0f / scale, Screen.height - screenCoord.y + 38.0f / scale, areaWidth, lineHeight * (connection.Links.Count + 1)));

GUILayout.BeginVertical();

GUILayout.BeginHorizontal();
GUILayout.Label("Distance", mGreenTextStyle, GUILayout.Width(distanceWidth));
GUILayout.Label("TX", mGreenTextStyle, GUILayout.Width(antennaWidth));
GUILayout.Label("RX", mGreenTextStyle, GUILayout.Width(antennaWidth));
GUILayout.Space(10);
GUILayout.Label("Target", mTargetTextStyle, GUILayout.Width(targetWidth));
GUILayout.EndHorizontal();

if (connection != null && connection.Links.Count > 0)
{
foreach (var link in connection.Links)
{
GUILayout.BeginHorizontal();

// Distance
if (source.DistanceTo(link.Target) > Math.Min(link.Transmitters.Max(a => (a.Omni != 0) ? a.Omni : a.Dish),
link.Receivers.Max(a => (a.Omni != 0) ? a.Omni : a.Dish)))
GUILayout.Label(RTUtil.FormatSI(source.DistanceTo(link.Target), "m"), mRedTextStyle, GUILayout.Width(distanceWidth));
else
GUILayout.Label(RTUtil.FormatSI(source.DistanceTo(link.Target), "m"), mGreenTextStyle, GUILayout.Width(distanceWidth));

// Transmitter status
// TODO: rework for non-Standard range models
if (!source.Antennas.Any(a => a.Powered && a.Activated))
GUILayout.Label("OFF", mRedTextStyle, GUILayout.Width(antennaWidth));
else if (link.Transmitters.Max(a => (a.Omni != 0) ? a.Omni : a.Dish) < source.DistanceTo(link.Target))
GUILayout.Label("RNG", mRedTextStyle, GUILayout.Width(antennaWidth));
else if (!source.HasLineOfSightWith(link.Target))
GUILayout.Label("LOS", mRedTextStyle, GUILayout.Width(antennaWidth));
else if (!link.Transmitters.Any(a => RangeModelExtensions.IsTargeting(a, link.Target, source)))
GUILayout.Label("AIM", mRedTextStyle, GUILayout.Width(antennaWidth));
else
GUILayout.Label("OK", mGreenTextStyle, GUILayout.Width(antennaWidth));

// Receiver status
// TODO: rework for non-Standard range models
if (!link.Target.Antennas.Any(a => a.Powered && a.Activated))
GUILayout.Label("OFF", mRedTextStyle, GUILayout.Width(antennaWidth));
else if (link.Receivers.Max(a => (a.Omni != 0) ? a.Omni : a.Dish) < link.Target.DistanceTo(source))
GUILayout.Label("RNG", mRedTextStyle, GUILayout.Width(antennaWidth));
else if (!link.Target.HasLineOfSightWith(source))
GUILayout.Label("LOS", mRedTextStyle, GUILayout.Width(antennaWidth));
else if (!link.Receivers.Any(a => RangeModelExtensions.IsTargeting(a, source, link.Target)))
GUILayout.Label("AIM", mRedTextStyle, GUILayout.Width(antennaWidth));
else
GUILayout.Label("OK", mGreenTextStyle, GUILayout.Width(antennaWidth));

GUILayout.Space(10);

// Target of link
GUILayout.Label(link.Target.Name, mTargetTextStyle, GUILayout.Width(targetWidth));

source = link.Target;
GUILayout.EndHorizontal();
}
}
else
{
// No connection information available
GUILayout.BeginHorizontal();
GUILayout.Label("No Connection Information", mGreenTextStyle, GUILayout.Width(areaWidth));
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}

GUILayout.EndVertical();
GUILayout.EndArea();
}

public void Draw()
{
if (mBackup != null)
Expand All @@ -212,7 +330,10 @@ public void Draw()
Vector2 screenCoord = ScreenSafeUI.referenceCam.WorldToScreenPoint(mBackup.TimeQuadrant.timeQuadrantTab.transform.position);
Rect screenPos = new Rect(5.0f / scale, Screen.height - screenCoord.y + 14.0f / scale, 50.0f / scale, 20.0f / scale);

GUI.Label(screenPos, DisplayText, mTextStyle);
if (GUI.Button(screenPos, DisplayText, mTextStyle))
{
mDisplayRoute = !mDisplayRoute;
}

screenPos.width = 21.0f / scale;
screenPos.x += 101 / scale;
Expand All @@ -224,6 +345,9 @@ public void Draw()
satellite.SignalProcessor.FlightComputer.Window.Show();
//ScreenMessages.PostScreenMessage(new ScreenMessage("[FlightComputer]: Not yet implemented!", 4.0f, ScreenMessageStyle.UPPER_LEFT));
}

if (mDisplayRoute)
DrawSignalRoute();
}
}
}
Expand Down

4 comments on commit e6b3a02

@Starstrider42
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @bk2w,

We've come back around to the issue of how to give players feedback on their network (RemoteTechnologiesGroup/RemoteTech#31), and while researching what had been discussed so far I came across your old pull request. Now that we have a non-frozen version of RemoteTech working, would you be willing to update your code so it can be PR'ed into the new repository?

@bk2w
Copy link
Owner Author

@bk2w bk2w commented on e6b3a02 Sep 26, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. It'll take a look at the updates and see what I can come up with.

@bk2w
Copy link
Owner Author

@bk2w bk2w commented on e6b3a02 Oct 13, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm most of the way through refactoring the diagnostics. I have both the text display, and persistent data storage working. I'm working on switching the NetworkManager from using A* on a signal path, to using Djikstra to find all paths; otherwise we only get diagnostics if we're on the vehicle when it loses connection. Also working on a map-overlay idea.

bk2w/RemoteTech@dbd9366 is the current state.

@Starstrider42
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. FYI, I've got my own refactor (RemoteTechnologiesGroup/RemoteTech#205) that will be merged with master in the next couple of days. While it shouldn't affect you (I've been careful to keep the interfaces unchanged, except in one case where it really had it coming) you should be aware of it.

Please sign in to comment.