Jump to content

alexalex

Members
  • Posts

    29
  • Joined

  • Last visited

Posts posted by alexalex

  1. On the plus side (though it's mostly big major downsides) he now has some experience in game development, can't be blamed for any of the KSP2 issues (he was only recently hired), and has a niche skill-set that should be attractive to a fair few game dev teams. There's a lot of games where realistic clouds and weather effects would result in marked improvements. Think FPS shooters or other games where a sandstorm rolls in reducing visibility, flight sims of one kind or another, etc.

    But I do hope he finds another job soon.

  2. 10 hours ago, uglyduckling81 said:

    This sounds awesome but unlikely to be in the base game.

    Sounds like a Satellite mod to me similar to the one we had in KSP1.

    The science over time is definitely the way to go as well. It's like that in Karbalism and is a far better system than base KSP science collection.

    Hopefully the game gets part failure as well.

    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.

  3. 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.

  4. 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();
    		}
    	}

     

  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. 8 minutes ago, Kerbart said:

    The good ole' we never said that, we surely suggested it but we don't think it's OUR fault that YOU interpreted our carefully crafted words in such a way as any normal person would.

    The only thing that was mentioned was:

    • We're lowering the frequency of updates to be able to spread the load between bug fixing and feature updates
    • Next update will be in June, and we're working on Science
    • Look! Shiny Science parts!

    But never once was somewhere said that this update would actually include Science. I wouldn't bet on it.

    At one point in time, "June" was mentioned. Nate then had to specify that this was not intended as "June 30" which is how the, by now quite salty, community unanimously interpreted it. My own take was the Friday before June 30 (as you know, the previous "cut and run" releases were on Friday COB and hoping the s###-storm dies down by the time Monday comes around), which is June 23, but surprisingly they picked June 20 as the release date instead.

    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. 3 hours ago, spacegamer7 said:

    Release-0.1 will be coming sometime this year, might be a while though because i know NOTHING about coding..

    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. 4 hours ago, Incarnation of Chaos said:

    So after three years they decided to go EA, and somehow managed to make this game suck down a RX 6800 for medium at 1080p.

    Full disclosure, I meet the specs. Ryzen 9 3950X and a 6800 with 32GB of RAM. 

    That doesn't make me any less surprised at the sheer amount of compute power that Intercept has managed to make KSP2 use for graphics that honestly hardly look better than a 10 year old game. 

    I know I don't have to buy it in EA (wasn't planning on it), but I seriously doubt they're going to improve performance significantly over the years. KSP 1 improvement was from moving to DX11 from DX9 in the later versions, KSP2 really has nowhere similar to go from here.

    If nothing else, I hope we get a good postmortem of KSP2s development.  Until then, discuss below. 

    *Activates flame shield*

     

    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.

     

  11. 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.

    Untsssitled.png

    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;
    				}
    			}
    		}

     

  12. 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;
    			}

     

  13. 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 -

    Untitledd.png

    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;
    			}

     

  14. 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.

  15. @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.

  16. @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?

×
×
  • Create New...