Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by alexalex

  1. There isn't actually any satellite mod that does this, though I'm working on creating a science only version of Kerbalism that does this among having various other improvements (I've got this part all worked out and fully functional though it was an absolute PITA to code). It's why I asked whether something like this would be in KSP 2, since when I read about the science update I immediately thought of what I'd recently finished coding and how something similar would be a vast improvement over KSP 1 that KSP 2 could include.
  2. So I have a couple questions... How will the experiments work? Will they be over time experiments that can take anything from minutes to years (hopefully)? And if so how does that interact with the satellite data transmission system? For example if I have a relay network set up around a planet and start sending data from a vessel on the surface will it consume bandwidth across the network, and so reduce how much is available for other vessels linked to that network? There's the possibility for a lot of interesting dynamics and interactions there.
  3. 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(); } }
  4. Can't see the log because its too big for github to show. But have you tried used debug.log to log to the console to determine the line of code that's causing the error?
  5. 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.
  6. 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(); } } }
  7. FYI even if they were still only bug fixing, the frequency of updates would still slow down. Dev's fix the big high impact easy to fix bugs first. The big high impact hard to fix bugs usually aren't bugs at all but rather relate to issues involving deep fundamental code design and require a lot more work since a hefty chunk of code has to be rewritten. That results in slower updates.
  8. You can do this through a module manager cfg file since stock ksp already has an upgrades feature built into it and module manager can take advantage of that. It's the simplest and easiest way without the need to do any c# hard coding. There's two parts to it. First you need to specify the tech node at which the upgrade unlocks at via PARTUPGRADE and secondly add the upgrade itself to the part config file via UPGRADES. https://github.com/rspeed/Porkjet-Parts-Overhaul/releases The above mod while old adds upgrades to existing parts so you should be able to follow those examples. The link below also contrains lots of useful info and links to more mods containing part upgrades.
  9. Lol. As someone fairly new to coding myself and who's been teaching myself the ins and outs of how to code for KSP1 (I've still got a long way to go), you'll want microsoft visual studio which is free and to download some existing simple mods to see how they work internally. C# as a language makes sense but like any language you'll need to know its grammar, syntax, and structure to use it properly. I'd also suggest using bing chatgpt as it can answer questions much faster than the hours it might take you to trawl through stackoverflow for an answer (this forum is pretty dead for getting answers on coding questions), but bear in mind its not always right. Good luck!
  10. I have not done it myself but maybe via FlightGlobals.ActiveVessel.transform?
  11. There's definitely been a boost to recent player count numbers. https://steamcharts.com/app/220200#1y
  12. Have you ever coded anything? Its pretty clear this game is in the early stages (probably shouldn't be released just yet) with missing core fundamentals such as heat transfer etc, and as such it looks to be very unoptimized. Personally, I think they are releasing it now because those are the orders from on high they have received rather than thinking its ready themselves which explains the current state of things. It also doesn't take very much at all for a game, any game, to slow a comp to a crawl. Just one bad piece of code will do it, and clearly given the letter from Nate he seems to know that there are some big bad pieces of code in there. So personally I don't think its the end of the world for KSP2 just yet, rather that its unfortunately following the trend of a lot of modern games and releasing before they should be due to shareholder and corporate pressures. Myself I will eagerly await EVE volumetrics, finish the mod update I'm working on, and play original KSP while KSP2 matures. Eventually KSP2 will surpass KSP1 but it won't be in the first few months after EA release.
  13. After bashing my head against the wall some more I found the fix for this - scrapping the part list method of hooking into KSPEvents entirely. It drastically simplified the code too.
  14. Going EVA scrambles the ordering of fields and events due to the ShowUpgradeStats event button disappearing on EVA, and how that interacts with KSP's own internal part field/event ordering system. To solve this I've made the ShowUpgradeStats button permanent, but the problem is that this then causes buttons on different parts to mix and duplicate while other buttons that should unload don't. I did find this old post where someone else was having the same/similar issue as me but their solution didn't work when I tried to apply it to my code. So does anyone know how I can fix this duplication issue or another way I can make the original field/event order permanent? Here's the code I've been using for ShowUpgradeStats. public void Start() { List<Part> parts = FlightGlobals.ActiveVessel.parts; for (int i = 0; i < parts.Count; i++) { Part p = parts.ElementAt(i); foreach (BaseEvent ShowUpgradeStats in p.Events) { int id = ShowUpgradeStats.id; p.Events[id].guiActiveUnfocused = true; } } }
  15. Update : I figured it out though its probably not the most elegant method. I'm putting it out here anyway though in case its useful to someone else at some point. I used boolean true or false and get/set accessors so that a part window update gets triggered whenever false changes to true or vice versa. Like so - private bool _UpdateGUI; public bool UpdateGUI { get { return _UpdateGUI; } set { if (value != _UpdateGUI) { part.PartActionWindow.displayDirty = true; } _UpdateGUI = value; } } // And public virtual void FixedUpdate() { if (Lib.IsEditor() && sample_amount > 0) { Capacity = sample_amount.ToString("F2") + " " + Local.SCIENCEARCHIVE_samples; Fields["Capacity"].guiActiveEditor = true; } if (Lib.IsFlight() && (remainingSampleMass / ExpInfo.SampleMass) > 0) { Capacity = (remainingSampleMass / ExpInfo.SampleMass).ToString("F2") + " " + Local.SCIENCEARCHIVE_samples; Fields["Capacity"].guiActive = true; UpdateGUI = false; } else if (Lib.IsFlight() && (remainingSampleMass / ExpInfo.SampleMass) <= 0) { Fields["Capacity"].guiActive = false; UpdateGUI = true; }
  16. The code I have makes changes to part GUI's. But it ends up looking odd in open part GUI's as the window doesn't automatically resize and refit to the changes, so unless I manually refresh I get odd overlaps like this - How do I force it to reload the open part GUI every time I make changes to it? Here's the relevant bit of my code. public virtual void FixedUpdate() { if (Lib.IsEditor() && sample_amount > 0) { Capacity = sample_amount.ToString("F2") + " " + Local.SCIENCEARCHIVE_samples; Fields["Capacity"].guiActiveEditor = true; } if (Lib.IsFlight() && (remainingSampleMass / ExpInfo.SampleMass) > 0) { Capacity = (remainingSampleMass / ExpInfo.SampleMass).ToString("F2") + " " + Local.SCIENCEARCHIVE_samples; Fields["Capacity"].guiActive = true; } else if (Lib.IsFlight() && (remainingSampleMass / ExpInfo.SampleMass) <= 0) { Fields["Capacity"].guiActive = false; }
  17. I need a bit of help on some Kerbalism syntax that I hope someone more knowledgeable than I can help me on. double availableDataCapacity = drive.FileCapacityAvailable(); int availableSlots = Lib.SampleSizeToSlots(drive.SampleCapacityAvailable()); if (Lib.IsFlight()) { // show TakeData eva action button, if there is something to take Events["TakeData"].active = !drive.Empty(); // show StoreData eva action button, if active vessel is an eva kerbal and there is something to store from it and if there is capacity to store something. Vessel v = FlightGlobals.ActiveVessel; Events["StoreData"].active = !IsPrivate() && availableDataCapacity > 0 && v != null && v.isEVA && !EVA.IsDead(v); } Both the main vessel and the active EVA kerbal have drives on them. I want to specificy that StoreData is active only when the drive on the active EVA kerbal is not empty. However inserting !drive.Empty() like so - Events["StoreData"].active = !IsPrivate() && availableDataCapacity > 0 && v != null && v.isEVA && !EVA.IsDead(v) && !drive.Empty(); specifies the drive on the main vessel rather than the one on the active EVA kerbal. So what would I use so that it checks against the kerbal's drive rather than the one on main vessel? The full set of code for the module is here if it helps.
  18. @Stone Blue I've already looked into that but it seems that in Mechjebs case its not using a generic module manager or KSP function but rather that its referencing specific code within the Mechjeb .dll to do it. So its specific to Mechjeb only and diving into that and adapting that code to my own use is unfortunately beyond my ability, novice modder that I am. So I'm hoping someone knows of a way to gate keep a module behind a tech requirement without resorting to C# code.
  19. I have another question in my modding adventures. Is there a way in module manager to set a tech unlock requirement for a module on a part, similar to the way you can gate keep parts themselves behind tech requirements?
  20. That would be @Gameslinx sort of thing I would think. Put volcano surface features on top of existing mountains via parallax.
  21. @Gotmachine, I am trying to fix some of the issues and bugs with the KerbalismScienceOnly config file. I've got it working decently but I'm running into an issue where there are game parts that have multiple different experiments on them via the configure property, but there doesn't seem to be a way to associate them all to the same HardDrive module, meaning I have to create a separate HardDrive for each experiment on the part which is very messy. Is there a way to set them all to a single HardDrive or an easy change I can make in the Kerbalism.dll to allow it?
  22. OK I have another question, I am trying to mod Kerbalism to fix some of the issues it has. I can use experiment_id to input a single experiment field, in this case dmbathymetryscan, to the HardDrive module, but how do I input multiple experiments to that module? I can't input multiple experiment_id's, so I need a way around it so is there a way to make experiment_id = X where X = experiment A plus experiment B plus experiment C?
  • Create New...