Jump to content

Need help with Vectrosity and VectorLine.


Recommended Posts

I am trying to make the satellite and relay system operate a bit like how data connections work in real life so that experiments consume antenna bandwidth while antennas provide network capacity.  So that each additional experiment that is being run would consume bandwidth and reduce the available capacity of the satellite relay network that it is on (I have this part mostly done).

But to make it work I need an easy to understand way to show the KSP player what is going on, and I'm running into trouble with the graphical interface part.  I can draw lines between the start and end points of a particular satellite relay network, but whenever I rotate the camera position the lines jitter and wobble about and I have no idea what's causing it.  Vanilla KSP doesn't do this so it's definitely something to do with my code.  Anyone know what's going on?

public class CommViewer : CommNetUI
	{
		public void Update()
		{
			if (line != null) VectorLine.Destroy(ref line);

			if (Monitor.commStatus != "<b> <<  Available Bandwidth  >> </b>") return;

			var vesselList = new List<Vessel>();
			foreach (Vessel v in FlightGlobals.Vessels)
			{
				if (v.connection != null && !v.connection.ControlPath.First.end.isHome)
				{
					Vessel endVessel = CommHandlerCommNetBase.CommNodeToVessel(v.Connection.ControlPath.First.end);
					vesselList.Add(endVessel);
				}
			}

			CommPath path = null;
			foreach (Vessel v in FlightGlobals.Vessels)
			{
				if (v.connection != null && !vesselList.Contains(v))
				{
					path = v.connection.ControlPath;
				}
			}

			List<Vector3> points = new List<Vector3>();

			path.GetPoints(points, true);

			ScaledSpace.LocalToScaledSpace(points);

			CreateLine(ref line, points);

			line.SetColor(Color.Lerp(new Color(0f, 1f, 1f), Color.clear, 0.3f));

			if (MapView.Draw3DLines)
			{
				line.SetWidth(lineWidth3D);
				line.Draw3D();
			}
			else
			{
				line.SetWidth(lineWidth2D = 1f);
				line.Draw();
			}
		}
	}

 

Edited by alexalex
Link to comment
Share on other sites

Update :  Looking further at it appears that whenever the camera position moves the line lags behind where it should be, and the jitter is it jumping ahead and trying to catch up to where it should be, instead of it being fixed to the vessel coordinates and moving smoothly with them.  Then when I stop moving the camera it catches up which is why there is no jitter then.  But I still don't know what is causing it.

Link to comment
Share on other sites

  • 2 weeks later...

Update : Nothing I tried was able to solve the issue directly since it just seems to be hard baked into the KSP code.  The only way I found around it was to either override the UpdateDisplay() method of CommNetUI, or joyride on top of it at runtime which is what I ended up doing, since that allowed me to code out a mod conflict.  On the plus side I think I'm getting close to being able to release something.  For posterity here is the code I ended up using.  Now compare this to the *short* class I initially wrote above...

[HarmonyPatch]
	public static class CommNetPatch
	{
		private static CommViewer commViewer;

		// prefix patch method
		[HarmonyPrefix]
		public static void PreFix()
		{
			if (commViewer == null)
			{
				commViewer = new CommViewer();
			}

			commViewer.LineDisplay();
		}

		// target method that determines which method to patch
		[HarmonyTargetMethod]
		public static MethodBase TargetingMethod()
		{
			// conditional that checks if the CommNetConstellation mod is present
			bool hasCNC = false;

			foreach (var a in AssemblyLoader.loadedAssemblies)
			{
				if (a.name == "CommNetConstellation") // check for CNC
				{
					hasCNC = true;
					break;
				}
			}

			// returns the appropriate method to patch depending on if CommNetConstellation is present
			if (hasCNC)
			{
				return AccessTools.Method(Type.GetType("CommNetConstellation.CommNetLayer.CNCCommNetUI, CommNetConstellation"), "UpdateDisplay");
			}
			else
			{
				return AccessTools.Method(typeof(CommNetUI), "UpdateDisplay");
			}
		}
	}

	public class CommViewer : MonoBehaviour
	{
		public void LineDisplay()
		{
			// destroy the old gameobject to delete existing lines so their positions can be refreshed
			GameObject oldLineObject = GameObject.Find("CommViewerLine");

			if (oldLineObject != null)
			{
				Destroy(oldLineObject);
			}

			if (Monitor.commStatus != "<b> <<  Available Bandwidth  >> </b>")
			{
				return;
			}

			// create a list of commlinks removing any duplicates
			HashSet<CommLink> uniqueLinks = new HashSet<CommLink>(new PrecisePositionComparer());

			foreach (Vessel v in FlightGlobals.Vessels)
			{
				if (v.connection != null)
				{
					foreach (CommLink link in v.connection.ControlPath)
					{
						if (!uniqueLinks.Contains(link))
						{
							uniqueLinks.Add(link);
						}
					}
				}
			}

			// iterate over the commlink list and store the vessel coordinates as well as startVessel in a new list via a tuple
			List<Tuple<Vector3, Vector3, Vessel>> linePositions = new List<Tuple<Vector3, Vector3, Vessel>>();

			foreach (CommLink link in uniqueLinks)
			{
				Vessel startVessel = CommHandlerCommNetBase.CommNodeToVessel(link.start);
				Vector3d start = ScaledSpace.LocalToScaledSpace(startVessel.GetWorldPos3D());

				Vessel endVessel = CommHandlerCommNetBase.CommNodeToVessel(link.end);

				Vector3d end;
				if (!link.end.isHome)
				{
					end = ScaledSpace.LocalToScaledSpace(endVessel.GetWorldPos3D());
				}
				else end = ScaledSpace.LocalToScaledSpace(link.end.precisePosition); // this only updates once per second so where possible use GetWorldPos3D() instead

				// create a new tuple containing the start and end vector3 coordinates and startVessel
				Tuple<Vector3, Vector3, Vessel> lineSegment = new Tuple<Vector3, Vector3, Vessel>(start, end, startVessel);

				// add the tuple to the list
				linePositions.Add(lineSegment);
			}

			// create a parent GameObject for the lines
			GameObject lineObject = new GameObject("CommViewerLine");
			UnityEngine.LineRenderer line = lineObject.AddComponent<UnityEngine.LineRenderer>();

			// use a foreach loop to iterate over the list and create a child LineRenderer for each pair of coordinates
			foreach (Tuple<Vector3, Vector3, Vessel> tuple in linePositions)
			{
				GameObject childLineObject = new GameObject("ChildLine");
				childLineObject.transform.parent = lineObject.transform;
				UnityEngine.LineRenderer childLine = childLineObject.AddComponent<UnityEngine.LineRenderer>();

				// set the start and end positions of the line using tuple.Item1 and tuple.Item2
				childLine.positionCount = 2;
				childLine.SetPositions(new Vector3[] { tuple.Item1, tuple.Item2 });

				Camera cam = PlanetariumCamera.Camera;
				Vector3d cam3d = cam.transform.position;

				float start = (float)Vector3d.Distance(cam3d, childLine.GetPosition(0));
				float end = (float)Vector3d.Distance(cam3d, childLine.GetPosition(1));

				// set the line width so it scales properly with zoom level
				childLine.startWidth = start * 5 / 1000;
				childLine.endWidth = end * 5 / 1000;

				childLine.material = CommNetUI.TelemetryMaterial;
				childLine.material.SetTexture("lineTex", CommNetUI.TelemetryTexture);

				// Use tuple.Item3 to access the startVessel so we can make the line color vary with signal strength
				Vessel startVessel = tuple.Item3;
				float signalStrength = (float)startVessel.KerbalismData().Connection.strength;

				(Color startColor, Color endColor) = MixColors(signalStrength);

				// now make the line nice and pretty
				SetColorGradient(childLine, startColor, endColor);

				if (MapView.Draw3DLines)
				{
					childLine.gameObject.layer = 31;
					childLine.useWorldSpace = true;
				}
				else
				{
					childLine.gameObject.layer = 10;
					childLine.useWorldSpace = false;
				}
			}
		}

		public (Color, Color) MixColors(float percentage)
		{
			// define the two pairs of colors to mix
			Color color1a = Color.Lerp(new Color(0f, 1f, 0f, 1f), Color.clear, 0.3f);
			Color color1b = Color.Lerp(new Color(1f, 0f, 0f, 1f), Color.clear, 0.3f);

			Color color2a = Color.Lerp(new Color(0.004f, 0.196f, 0.125f), Color.clear, 0.3f);
			Color color2b = Color.Lerp(new Color(0.310f, 0f, 0f, 1f), Color.clear, 0.3f);

			// calculate the percentage for the other color
			float otherPercentage = 1f - percentage;

			// mix the first pair of colors using the percentage and its complement
			Color mixedColor1 = color1a * percentage + color1b * otherPercentage;

			// mix the second pair of colors using the same percentage and its complement
			Color mixedColor2 = color2a * percentage + color2b * otherPercentage;

			// return the two mixed colors
			return (mixedColor1, mixedColor2);
		}

		public static void SetColorGradient(UnityEngine.LineRenderer childLine, Color startColor, Color endColor, float startAlpha = 1, float endAlpha = 1)
		{
			Gradient gradient = new Gradient();
			gradient.SetKeys(
				new GradientColorKey[] { new GradientColorKey(startColor, 0.0f), new GradientColorKey(endColor, 1.0f) },
				new GradientAlphaKey[] { new GradientAlphaKey(startAlpha, 0.0f), new GradientAlphaKey(endAlpha, 1.0f) }
			);
			childLine.colorGradient = gradient;
		}
	}

	class PrecisePositionComparer : IEqualityComparer<CommLink>
	{
		public bool Equals(CommLink x, CommLink y)
		{
			// Check if x and y are null
			if (x == null && y == null)
				return true;
			if (x == null || y == null)
				return false;

			// compare the start and end precise positions of x and y
			return x.a.precisePosition == y.a.precisePosition && x.b.precisePosition == y.b.precisePosition;
		}

		public int GetHashCode(CommLink obj)
		{
			// return a hash code based on the precise positions of obj
			return obj.a.precisePosition.GetHashCode() ^ obj.b.precisePosition.GetHashCode();
		}
	}

 

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...