Cephei

The official unoffical "help a fellow plugin developer" thread

Recommended Posts

@JPLRepo So these RequestResource/TransferResource only use is if I care about flow states, flow modes and stacking.... I didn't realize I could just do this:

void fromEVA(GameEvents.FromToAction<Part, Part> data)
{
  // add the leftover monoprop back to the pod
  data.to.RequestResource("MonoPropellant", -data.from.Resources.list[].amount);
}

 

Edited by ShotgunNinja

Share this post


Link to post
Share on other sites
45 minutes ago, ShotgunNinja said:

How can I avoid that event? What if I call TransferResource instead, that i understand must be some kind of old version of RequestResource without flow mechanics...

EDIT: nope, it seems to obey flowState. Screw that, lets this damn event fire and who cares

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.

22 minutes ago, JPLRepo said:

Why don't you just take the resource yourself? Just do the math and add/subtract the resource.amount yourself from each.
you don't "Have to" use RequestResource or TransferResource

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

 

 

5 minutes ago, ShotgunNinja said:

So these RequestResource/TransferResource only use is if I care about flow states, flow modes and stacking.... I didn't realize I could just do this

No, all TransferResource cares about is flowMode (in, out, both, none).  RequestResource also honours the flowState and the ResourceFlowMode (stack, all vessel etc.).

Edited by Padishar
  • Like 1

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
11 minutes ago, JPLRepo said:

No way to see what portraits are available in the class except attaching your own class toa prefab (not very efficient at all)

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

Share this post


Link to post
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.

Share this post


Link to post
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.

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

Yes the lack of information is scary. And also I agree the public API has to be an inviolable contract. Right now you get things like temporary variables, values cached locally, etc... all happily exposed to the public API. Its a mess.

Share this post


Link to post
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.

  • Like 2

Share this post


Link to post
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.

Share this post


Link to post
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.

Share this post


Link to post
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.

Share this post


Link to post
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?
		}
	}
}

 

Share this post


Link to post
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.

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

Thank you so much @Padishar!  That makes much more sense.  I didn't realize its variables were initialized at 0 when the object is created.  Again, thank you!

Share this post


Link to post
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

Share this post


Link to post
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.

Share this post


Link to post
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.

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now