Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

6 minutes ago, Padishar said:

I suspect very little will get upset about the event firing.  Someone was asking about how to detect when the user toggled the flowState on a part the other day but I doubt you would upset whatever they were doing.

However, TransferResource definitely shouldn't take any notice of flowState.  E.g.

data.from.TransferResource("EVA Propellant".GetHashCode(), amount);

...should definitely work in this case though you should probably only get the id of the resource once and store it.

Please don't even consider doing this.  TransferResource (that RequestResource and various other bits of KSP code calls to actually add or remove resources) now fires some very important events when parts change from full<->non-full and empty<->non-empty and you doing it yourself will skip this which will break stock and mod code (perhaps not immediately, but certainly when the resource overhaul happens in 1.2).

Pretty sure I've seen mods do that in the past. Which is why i suggested it.
If the new gameevents and resource overhaul happens I suspect Squad will lock down the resource.amount field then. right now it's public.
But then, a lot of changes aren't thoroughly thought through I think.. EG: The new kerbalPortraitGallery class. No way to see what portraits are available in the class except attaching your own class toa prefab (not very efficient at all) and then unable to therefore know if you are duplicating portraits, etc... Anyway, off track.
Like @Padishar said @ShotgunNinja maybe best not to take the resource directly. But yes you will fire the new game event when you change the resource and I don't think there is a way to stop it.

Edited by JPLRepo
Link to comment
Share on other sites

1 minute ago, JPLRepo said:

Pretty sure I've seen mods do that in the past. Which is why i suggested it.
If the new gameevents and resource overhaul happens I suspect Squad will lock down the resource.amount field then. right now it's public.

Just because something is public doesn't mean that you shouldn't care about how the API is intended to work and, instead, do what you like with it when there is a perfectly good function to do what you want (TransferResource in this case).

There is no if about it, the addition of these events (and the opening up of some other resource related bits) is the first step in the overhaul, intended to allow certain people to experiment with various ways of optimising the resource handling.

Link to comment
Share on other sites

Just now, ShotgunNinja said:

@JPLRepo, @Padishar Guy thanks again for the extremely useful info. These things are not really obvious at first glance. BTW what is this 'resource overall of 1.2'? First time I've eard of it.

It was mentioned in a recent devnote.  Basically, RequestResource is horribly inefficient, especially for the all vessel and stage priority flow modes, some large vessels can easily spend more than 50% of the CPU time in that function which effectively halves the frame rate.  There are various optimisations that are planned but it was considered to be too much of a change to include in 1.1 what with all the other Unity5 changes so it got pushed back.

Link to comment
Share on other sites

@Padishar Thank you. A fast search in my codebase for 'RequestedResource' popped up 54 results, so I'm interested in this. Not that I did ever notice any slowdown at all from it honestly. Personally I'll prefer they focus on fixing the planet pong specular HIGH PRIORITY :rolleyes:. Those giant plastic lobes are immersion-breaking as hell.

Link to comment
Share on other sites

9 minutes ago, xEvilReeperx said:

I'm curious, what makes you think it's inefficient?

Adding a class to the prefab to build/populate and maintain your own list. This being more overhead than simply querying an existing list. I guess I am getting infuriated with that class because there are other things going on under the covers (which of course we can't look) that keeps re-creating Portraits after I destroy them. Anyway, onwards and upwards.

19 minutes ago, Padishar said:

Just because something is public doesn't mean that you shouldn't care about how the API is intended to work and, instead, do what you like with it when there is a perfectly good function to do what you want (TransferResource in this case).

There is no if about it, the addition of these events (and the opening up of some other resource related bits) is the first step in the overhaul, intended to allow certain people to experiment with various ways of optimising the resource handling.

Agree - in that should not assume public is fair game. But on the other hand, disagree, public should be fair game.
I believe in tight class defintiions. It shouldn't be a public set if the intention is to not directly modify the amount field.
I'd also LOVE some information on how the API is intended to work be published.

Link to comment
Share on other sites

I, uh, think I know why I broke it <blush>

EDIT: _How_ I broke it. Obviously I didn't intend to change the flow mode, but I did swap flowstate over to a property. Which is fine, because PartResoruce loads from confignode. Except for EVA kerbals, which load from prefab, which use Unity prefab deserialization which borks there. So the old flowstate is being reset.

Link to comment
Share on other sites

9 minutes ago, NathanKell said:

I, uh, think I know why I broke it <blush>

EDIT: _How_ I broke it. Obviously I didn't intend to change the flow mode, but I did swap flowstate over to a property. Which is fine, because PartResoruce loads from confignode. Except for EVA kerbals, which load from prefab, which use Unity prefab deserialization which borks there. So the old flowstate is being reset.

Thanks for the info. That explains that then.

Link to comment
Share on other sites

Hello everyone!  I'm running into some problems creating a simple box with some text that I can move around.  Or rather, I'm having a problem *not* creating a box I can move around.  My goal is to have a small box that appears *only* during the flight scene (which I believe is after I press the spacebar on the launch pad).  I have my class tied to a part per a tutorial I found on the wiki (i.e. module name is the same as my class name.  However, my dragable box is appearing as soon as the part is loaded in the editor despite the if condition on line 12:

if (HighLogic.LoadedScene == GameScenes.FLIGHT)

From the KSP.log file, I'm seeing a lot of  [ThisMod is aborting OnStart!]  which means that the OnGUI method should not be executing.  And yet, it is creating a small box.  My code is below:

using System;
using UnityEngine;

namespace GUITest
{
	public class GUITest : PartModule
	{
		public Rect _windowPosition = new Rect();

		public override void OnStart(StartState state){//Should initialize when scene changes

			if (HighLogic.LoadedScene == GameScenes.FLIGHT) {//Make sure not in editor (aka in flight scene)
				OnGUI ();//Calls method to create blank rectangle...but how big is the rectangle?
				print ("Starting Rectangle!");
				OnWindow(10);
			} else
				print ("[ThisMod is aborting OnStart!]");//Print to log in case above doesn't execute

		}

		private void OnGUI(){//THis method creates a blank rectangle...I think
			if (this.vessel == FlightGlobals.ActiveVessel)
				_windowPosition = GUILayout.Window (10, _windowPosition, OnWindow, "This is a Title!");
			print ("OnGUI Executed!");
			//Concern:_windowPosition is never defined and yet is used to define _windowPosition.  WHY is this not an error?
			else
				print ("[ThisMod is aborting OnGUI!]");//Print something if above doesn't work
		}

		private void OnWindow(int windowId){//This mod populates the blank rectangle...I think
			GUILayout.BeginHorizontal (GUILayout.Width (250f));
			//GUILayout.Label ("MyState: "+currState);
			GUILayout.Label("This is a label!");
			GUILayout.EndHorizontal ();

			GUI.DragWindow ();//Makes the rectangle drag-able?
		}
	}
}

 

Does anyone have any idea why this would be happening?  I'm completely in the black.

Link to comment
Share on other sites

OnGUI is called automatically by Unity multiple times per graphics frame.  You should not be calling it directly from OnStart or from anywhere else.

The OnWindow function is the handler function for the GUILayout.Window you are creating in your OnGUI.  Again, you shouldn't be calling it directly from anywhere.

Link to comment
Share on other sites

@Padishar I'm afraid I am still new to the language of C# (and object-oriented programming in general).  If I understand you, OnGUI and OnWindow are methods that are called by another class and (at least for OnGUI) get called periodically by the game, similar to OnStart.  They should be treated as methods I can use to call methods I create (similar to that of OnStart in my code above).  Is that correct?

I tested with taking out OnStart and it is working better.  But now I have a few other questions.

1)  By removing the OnStart method above (because it was not necessary for this), how does the label from OnWindow know to associate with the window created by OnGUI?  Before, I had thought it was because they both shared the same window ID (10).  But with that portion of code taken out, I can't see anything in my code to associate the two.  Is OnWindow called by OnGUI?  But again, how does OnGUI know to call my additions to OnWindow?

2)  In my code, _windowPosition is called and defined.  However, it is used in its own definition.  Why does this not generate an error?  In my mind, it should be similar to this:

y = 10

x = y + x

print(x)

What is x's value?  It can't be known because x is never defined a value.  Note that I mean the above in the C# sense of assigning value, not the equivalence operator.  For reference, my new code (which appears to work correctly):

using System;
using UnityEngine;

namespace GUITest
{
	public class GUITest : PartModule
	{
		public Rect _windowPosition = new Rect();

		public void OnGUI(){//THis method creates a blank rectangle...I think
			if (this.vessel == FlightGlobals.ActiveVessel && HighLogic.LoadedScene == GameScenes.FLIGHT) {
				_windowPosition = GUILayout.Window (10, _windowPosition, OnWindow, "This is a Title!");
				print ("OnGUI Executed!");//Spams log if successful
			}
			//Concern:_windowPosition is never defined and yet is used to define _windowPosition.  WHY is this not an error?
			else
				print ("[ThisMod is aborting OnGUI!]");//Spams log if unsuccessful
		}

		//Concern:  How does OnWindow associate with window above?
		public void OnWindow(int windowId){//This mod populates the blank rectangle...I think
			GUILayout.BeginHorizontal (GUILayout.Width (250f));
			GUILayout.Label("This is a label!");
			GUILayout.EndHorizontal ();

			GUI.DragWindow ();//Makes the rectangle drag-able?
		}
	}
}

 

Link to comment
Share on other sites

2 minutes ago, Tralfagar said:

But with that portion of code taken out, I can't see anything in my code to associate the two.  Is OnWindow called by OnGUI?  But again, how does OnGUI know to call my additions to OnWindow?

Because you pass the OnWindow function to the GUILayout.Window function to create the window.  This basically says "create me a window and call the function I've given you to get the contents".

4 minutes ago, Tralfagar said:

In my code, _windowPosition is called and defined.

You define it initially as a new Rect which will have all the values it contains set to 0.  The GUILayout.Window function uses the rectangle you pass in to decide where and how big to create it but it can end up being different to what you specify.  Because of this it returns the rectangle that it has actually used and you store this away so next time you are passing the correct values.  This is important for GUI.DragWindow to work as the rectangle returned will move on the screen when the window is dragged.

Link to comment
Share on other sites

I have an idea for a 1.1 mod and would like to ask some first-level questions about what's possible.

When storing/collecting/transmitting science, the notification text appears in a bounded-box to the upper-left.  I feel the text is too large and it's center aligned; the 1.0.5 format was less intrusive.  I'd prefer smaller text (perhaps even a different type face), left-justified, and maybe different colour coding based on the type of message.  Lastly, if such a mod were to exist, I figure it should be able to give the user control of all these formatting elements plus position this notification space anywhere the user would prefer.

Is such a mod possible? Has anything similar been built? If not, where would I start my research?  Consider me greener than Jool.

(A lot of docs talk about parts -- modelling, shaders, textures -- and it's hard to wade through that when I know what I'm looking for has no parts at all).

 

Thanks much.

Edited by Trann
Link to comment
Share on other sites

All right, I am thoroughly perplexed.  I'm trying to print the number of crew (an integer) to make sure I am using the correct format (the commented-out portion).  However, I believe I need to first convert it to a string.  I had thought all integer objects had a method (ToString()) which converted them to a string but I'm not so sure now.  Per this website, it looks like ToString() should be in the System namespace.  Is this correct?  When I try to convert the integer to a string, I get this error message in ksp.log (as well as the debug screen):

[EXC 21:57:19.572] FileNotFoundException: Could not load file or assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.

Has anyone here seen anything similar?  Am I doing something wrong with my code:

 

using System;

using UnityEngine;

using KSP;

namespace GUITest
{
	public class GUITest : PartModule
	{public override void OnUpdate()
		{
			/*if (FlightGlobals.ActiveVessel.loaded == true) {
				string numCrew = FlightGlobals.ActiveVessel.GetCrewCount ().ToString();//update string with crew info?
				print ("[MyMod] calculating crew");
			} else {
				print("[MyMod] not calculating crew");
			*/
			int myInt = 6;//test case; use integer
			string myString;
			myString = myInt.ToString ();//ToString() should be in namespace System, right?  Exception/Error in log from this.
			print (myString);//Does not execute

		}
	}
}

 

Edited by Tralfagar
Added hyperlink/System namespace source
Link to comment
Share on other sites

56 minutes ago, Tralfagar said:

All right, I am thoroughly perplexed.  I'm trying to print the number of crew (an integer) to make sure I am using the correct format (the commented-out portion).  However, I believe I need to first convert it to a string.  I had thought all integer objects had a method (ToString()) which converted them to a string but I'm not so sure now.  Per this website, it looks like ToString() should be in the System namespace.  Is this correct?  When I try to convert the integer to a string, I get this error message in ksp.log (as well as the debug screen):

[EXC 21:57:19.572] FileNotFoundException: Could not load file or assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.

Has anyone here seen anything similar?  Am I doing something wrong with my code:

 


using System;

using UnityEngine;

using KSP;

namespace GUITest
{
	public class GUITest : PartModule
	{public override void OnUpdate()
		{
			/*if (FlightGlobals.ActiveVessel.loaded == true) {
				string numCrew = FlightGlobals.ActiveVessel.GetCrewCount ().ToString();//update string with crew info?
				print ("[MyMod] calculating crew");
			} else {
				print("[MyMod] not calculating crew");
			*/
			int myInt = 6;//test case; use integer
			string myString;
			myString = myInt.ToString ();//ToString() should be in namespace System, right?  Exception/Error in log from this.
			print (myString);//Does not execute

		}
	}
}

 

It looks like to me your target .NET framework is 4 KSP only suport .NET Framework 3.5.

Link to comment
Share on other sites

Hi all, and apologies for not reading all 85 pages of this thread prior to asking... (I *did* read what I thought was a representative sample, and hope I'm not duplicating a FAQ)

I have a lot of programming experience in a variety of languages, and even already some C# from developing an OSX application some years ago. So assume I'm at least literate about code-level things. But all of my experience (aside from that OSX app, and a couple Java apps) has been in Unix environments and I'm pretty thoroughly ignorant about the prerequisites and tools used to develop C-flavored stuff under microsoft windows, which is where I currently find myself.

So what I'm hoping for is a little flowchart or sequence I can follow to get my first project to compile; I am assuming at first that I'll get all the API info I need from reading other people's plugins and from the couple of forum threads that list API stuff, what I need here is a list of TOOLS that I must have installed and what order to use them in.

Something similar in format to this:

  1. Install software framework X, version blah blah.
  2. Get Unity, version blah, {must have pro version/free version will suffice}
  3. Editor to use (any of my choice, or does a certain IDE have huge advantages?)
  4. Start a project in TOOL-blah from Unity package
  5. Be sure to set variables foo bar and baz in the project properties
  6. <write code>
  7. Compile project (from IDE? Some Unity program? Generic C# compiler? (which one? costs money? can I use some GNU software instead?))
  8. Copy to KSP GameData folder and test.

So far I have the free version of Unity installed (but haven't done anything with it yet) and I see from @JPLRepo in the prior post that I need .NET 3.5. I've read the add-on posting rules, skimmed the API documentation threads... but it's been a few years since I've programmed at all, and as I said never in a Windows environment.

Pointers to documentation elsewhere are welcome.

And I should note I am NOT planning on doing ANY 3d modeling, texturing, or animation... I'll re-use existing parts and/or get someone else to do that bit if needed, it's not something I'm planning on learning.

My "hello world" kind of project is going to be a simple on-screen clock that can be displayed in all scenes, providing the real-world/system (not ksp-internal) time so I don't tab out of ksp so often to check the time. :)

Edited by Newnard
left out a few words.
Link to comment
Share on other sites

@Newnard You don't need Unity at all for plugins.  The only thing you need is a copy of KSP and a C# compiler - Xamarin Studio or Visual Studio Community Edition (both free, both now owned by Microsoft).

You need to set the compiler to target .NET 3.5 (default is 4.0), but other than that there's nothing special.  The .dll you create can just be copied to GameData directly, but convention is GameData/Modname/Plugins/modname.dll.

http://forum.kerbalspaceprogram.com/index.php?/topic/85372-mod-development-links-compilation-some-links-do-not-work-formatting-broken/

https://github.com/taraniselsu/TacExamples

Link to comment
Share on other sites

@AliceTheGorgon

I got some help from the KSPModders IRC on the general process.  I have not been able to test it yet but from what I understand, it should go something like this:

1)  Install Mono Develop (which you have done)

2) Download the proper version of Mono (I believe 3.12.1 was suggested) as a tarball

3)  Compile it 

4) go to Preferences in MonoDevelop, under .NET Framework or something similar, choose recently compiled file

Edited by Tralfagar
Fixing the formatting
Link to comment
Share on other sites

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