Cephei

The official unoffical "help a fellow plugin developer" thread

Recommended Posts

@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

Share this post


Link to post
Share on other sites

@AliceTheGorgon

Now that I'm home, I can go a little more in depth.  I got Mono tarball from here and I'm currently following the instructions on how to compile Mono on Linux.  At the bottom of the page is the Parallel Mono Environments instructions.  I will be trying them after the installation finishes.

Did you have any luck with your install?

Share this post


Link to post
Share on other sites

@AliceTheGorgon

I think I may have originally downloaded the wrong mono file initially; it was loading as mono 4.5 for whatever reason, despite the file name being 3.12.1.  I've since tried with a fresh 3.12.1 and it looks like it is now correct.  I unzipped the tarball manually (right click -> Extract here).  I changed the active directory to the one just created by extracting the tarball.  Then I ran:

 

./configure --prefix=/opt/mono

make

sudo make install

I am able to load it in  

"Edit" -> "Preferences" -> "Projects" -> ".NET Runtimes"

However, the current Mono version does not change.  Further, when I attempt to change

"Project" -> "<project name> Options" -> "Build" -> "General" -> "Target Framework"

 to .NET 3.5, I am only presented with an option for .NET 4.5.  Here are a couple of images of what I am seeing.  You are talking about these menus, correct?

 

 

 

Did you overwrite Mono for your entire system or make a parallel install?  If you overwrote it for your whole system, do you see any adverse affacts (I may do this as well, then)?

Share this post


Link to post
Share on other sites

Is anyone using GameEvents.onVesselWasModified? I'm using it to detect parts coming off a vessel (intentionally or otherwise) and it was working fine in 1.0.5 but in 1.1 the callback is never triggered. I've looked at it a number of times and I don't see anything wrong. I've also moved it from OnStart to the first time OnUpdate is called ,in case OnStart was to early, without success. In 1.0.5 it would fire on parts being scraped of, undocked, decoupled and farings being jettisoned. Now in 1.1 none of those trigger the callback.

Share this post


Link to post
Share on other sites

@AliceTheGorgon

I think I see what happened and it was the same problem you were having:  I was trying to create a portable library.  I changed it to a .NET library under Other when creating a new solution (ctrl+shift+n).  Thank you very much for your help and patience.

Here is a brief recap in case anyone in the future should find this thread:

1)  Do NOT create a portable library.  Instead, under "Other", select "Library".

2)  Under Edit -> Preferences -> Project -> .NET Runtimes, I am not sure why, but Mono 4.2.3 needs to be selected as the .NET runtime (see picture 2).  I know .NET 3.5 is not supported by Mono 4.2.3 but if I select Mono 3.12.1, I receive a compile error (Message:  "Build failed. Unexpected binary element: 0").  Using Mono 4.2.3, I can compile and KSP reads it.

3)  Under Project -> [Project_Name] Option -> Build -> General, select Target Framework to Mono / .NET 3.5.  Again, the version of Mono I selected should not work but for whatever reason, it does.  I just confirmed that it works with the code at the end of this post (which previously gave an error when run; see the preceding posts).

 

 

using System;
using UnityEngine;
using KSP;


namespace GUITest
{
  public class GUITest : PartModule
  {
    public override void OnUpdate ()
    {
      int myInt = ;
      string myString;
      myString = myInt.ToString ();
      Debug.Log(myString);
    }
  }
}

 

Share this post


Link to post
Share on other sites

Hey everyone. Is there an easy way to have some code run when a savegame's Kerbin time reaches a certain value? I couldn't find anything in GameEvents.

Share this post


Link to post
Share on other sites
2 hours ago, Adamantium9001 said:

Hey everyone. Is there an easy way to have some code run when a savegame's Kerbin time reaches a certain value? I couldn't find anything in GameEvents.

Depends on how long you are wanting. If it's a short period of time you can do a delayed callback. The stock KSP code has some useful public methods for this.

base.StartCoroutine(CallbackUtil.DelayedCallback(x, new Callback(this.MethodToExecute)));

Where x is the number of seconds (yes you will have to calculate the differentce between when you want the callback and current game time).
MethodToExecute is the method you want called when the time is up. - NB: This won't persist if the user exits.

If the time you want to wait is lengthy, you probably have to store it somewhere and check against it in Update(), and persist the time you are waiting for across sessions.
 

Share this post


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

If the time you want to wait is lengthy, you probably have to store it somewhere and check against it in Update(), and persist the time you are waiting for across sessions.

I thought that might be the case.

Another question: do I need to worry about my game-saving code (bound to GameEvents.onGameStateSave) being triggered while Update() is still running in another CPU thread? More generally (if you can), is there a quick list of things I need to look out for in terms of threads tripping over each other? I've never done any multi-threaded programming.

Share this post


Link to post
Share on other sites
26 minutes ago, Adamantium9001 said:

I thought that might be the case.

Another question: do I need to worry about my game-saving code (bound to GameEvents.onGameStateSave) being triggered while Update() is still running in another CPU thread? More generally (if you can), is there a quick list of things I need to look out for in terms of threads tripping over each other? I've never done any multi-threaded programming.

Unity manages that for you. Update() won't be running if Unity is running OnSave cycle, etc. I've not used GameEvents.onGameStateSave yet as it is new to KSP 1.1.
Generally, depending on what kind of module it was you would use say OnSave for PartModules or ScenarioModule, (both of which have built in OnSave methods), etc.
Refer to the Unity manual (this thread generally isn't for Unity tutorials), there are plenty on the Unity site. http://docs.unity3d.com/Manual/ExecutionOrder.html
Also You can look at: http://forum.kerbalspaceprogram.com/index.php?/topic/60381-ksp-plugin-framework-plugin-examples-and-structure-v11-apr-6/
or the video tutorials, and the Plugin Development section, etc here: http://forum.kerbalspaceprogram.com/index.php?/topic/85372-mod-development-links-compilation-some-links-do-not-work-formatting-broken/

 

Share this post


Link to post
Share on other sites

To smooth out welding a bit more I want to add a new partmodule that will replace an existing one at runetime.

public void clearDecalModule()
{
	PartModuleList modules = part.Modules;
	PartModule pm;
	for(int i =0; i < part.Modules.Count; i++)
	{
		pm = part.Modules[i];
		if (pm is FlagDecal)
		{
			if (((FlagDecal)pm).textureQuadName == textureQuadName)
			{
				part.Modules.Remove(pm);
				Destroy(pm);
				break;
			}
		}
	}
	if(HighLogic.LoadedSceneIsEditor)
	{
		GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartTweaked, part);
		GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship);
	}
	else if(HighLogic.LoadedSceneIsFlight)
	{
		GameEvents.onVesselWasModified.Fire(vessel);
	}
}

Everything happens in the "public override void OnStart(StartState state)" and it runs very fine for itself, but just in the next frame I get an exception:

Quote

[EXC 23:42:54.211] ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
 System.Collections.Generic.List`1[PartModule].get_Item (Int32 index)
 PartModuleList.get_Item (Int32 index)
 Part.ModulesOnStart ()
 Part+.MoveNext ()

It indicates that the list of partmodules does not get updated, is there a workaround for fix this problem or an alternative route?

I appreciate every Adivce.

Share this post


Link to post
Share on other sites

@Alewx Don't modify Part.Modules in OnStart(), because KSP will still try to access indices that don't exist.  Do it in Start(), which is a Unity method and isn't iterating over the modules that way.

Share this post


Link to post
Share on other sites

@Alewx More info: I believe that the part determines the size of its modules, and then iterates over them to call OnStart(), so it will still try to iterate over n modules even though there are really only n-1 now (quite difficult to have a list change as you're iterating over it in general).

Share this post


Link to post
Share on other sites

@blowfish Thanks for the info, I give it a testrun and report back.

Update: Tested your suggestion and it works flawless so far, big thank you.

Edited by Alewx

Share this post


Link to post
Share on other sites

I am trying to add a custom category for my mod in the VAB/SPH but I can't get it to work. Here is what I have, please tell me I have made a stupid mistake that is easily solved. Worth noting KBParts.Count is 12 and for some reason when I format as code 'if(KBParts.Count > 0)' is showing as 'if(KBParts.Count > )'

using System.Collections.Generic;
using UnityEngine;
using KSP.UI.Screens;


namespace KerBalloons
{
    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    class KerBalloonsCatagory : MonoBehaviour
    {
        List<AvailablePart> KBParts = new List<AvailablePart>();

        void Awake()
        {
            KBParts.Clear();
            foreach (var KBPart in PartLoader.LoadedPartsList)
            {
                if (!KBPart.partPrefab) continue;
                if (KBPart.manufacturer == "KerBalloons")
                {
                    KBParts.Add(KBPart);
                }
            }

            Debug.Log("KerBalloons Part Count: " + KBParts.Count);
            if (KBParts.Count > )
            {
                GameEvents.onGUIEditorToolbarReady.Add(SubCategories);
            }
        }

        bool EditorItemsFilter(AvailablePart KBPart)
        {
            return KBParts.Contains(KBPart);
        }

        void SubCategories()
        {
            Debug.Log("Adding KerBalloons Catagory");
            var icon = PartCategorizer.Instance.iconLoader.GetIcon("cs_main");
            var filter = PartCategorizer.Instance.filters.Find(f => f.button.categoryName == "Filter by Function");
            PartCategorizer.AddCustomSubcategoryFilter(filter, "KerBalloons", icon, p => EditorItemsFilter(p));
        }
    }
}

 

Edited by JoePatrick1

Share this post


Link to post
Share on other sites

Okay noob-alert here, just in case you don't remember I have no idea what I'm doing.

I came across the mod WarpUnlocker, and wanted to make a slight modification to it. The source is in the zip and I've included it below (It's in the  public domain) because it's so simple. Note: The WarpUnlocker dll works in ksp 1.1.2, so I know it's not the mod's fault but mine.

Spoiler

using System;
using UnityEngine;

namespace WarpUnlocker
{

    [KSPAddon(KSPAddon.Startup.Flight, false)]
    public class WarpUnlocker : MonoBehaviour
    {

        public void Start()
        {

            TimeWarp timeWarp = (TimeWarp)FindObjectOfType(typeof(TimeWarp));

            for (int i = 0; i < timeWarp.warpRates.Length; i++)
                timeWarp.warpRates[i] = (float)Math.Pow(10, i);

            foreach (CelestialBody iCelestialBody in FlightGlobals.Bodies)
                for (int i = 0; i < iCelestialBody.timeWarpAltitudeLimits.Length; i++)
                    iCelestialBody.timeWarpAltitudeLimits[i] = 0;

        }

    }

}

 

So I (re-)followed the instructions for creating a new project in this helpful wiki page and instead of using the "hello Kerbin" stuff I pasted WarpUnlocker's source into my project. I hit F7 in MonoDevelop and - somewhat to my surprise - it compiled and made me a DLL. SWEET.

I took that DLL and copied it over the WarpUnlocker DLL that was originally in my KSP install (barebones, no mods but this one) and found that while the mod itself seems to be installed and running, it doesn't DO anything. The time warp constraints are still there and the first time warp level is 5, not 10 (which the original DLL did).

So, I edited the source to allow printing to the log file (like in the wiki page's tutorial) and even THOSE aren't outputting to the log file. It's like the mod loads but doesn't run.

Any idea what I'm doing wrong? Remember to use "Captain Dummy Speak."

Edited by 5thHorseman

Share this post


Link to post
Share on other sites
1 hour ago, 5thHorseman said:

So, I edited the source to allow printing to the log file (like in the wiki page's tutorial) and even THOSE aren't outputting to the log file.

There is a section fairly near the start of the log that shows the loading of the various plugins.  Your best bet is probably to upload a complete output_log.txt/player.log so we can see what is happening.  One possible cause, given you say the real mod works, is that you're targetting the wrong version of .net it needs to be version 3.5.

 

Edited by Padishar

Share this post


Link to post
Share on other sites
1 hour ago, Padishar said:

There is a section fairly near the start of the log that shows the loading of the various plugins.  Your best bet is probably to upload a complete output_log.txt/player.log so we can see what is happening.  One possible cause, given you say the real mod works, is that you're targetting the wrong version of .net it needs to be version 3.5.

 

Here's the output_log.txt (zipped) of me loading the game, jumping to an already-orbiting ship from the tracking station, and hitting time warp up to 50x where KSP told me that was fast enough.

http://pulpaudio.com/ksp/output_log.zip

And here's the latest source code with the outputs just to be sure.

Spoiler

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace WarpUnlocker
{

	[KSPAddon(KSPAddon.Startup.Flight, false)]
	public class WarpUnlocker : MonoBehaviour
	{
		public void Start()
		{
			print ("WarpUnlocker: Start");
			TimeWarp timeWarp = (TimeWarp)FindObjectOfType(typeof(TimeWarp));
			print ("WarpUnlocker: Set Timewarp");

			for (int i = 0; i < timeWarp.warpRates.Length; i++) 
			{
				print ("WarpUnlocker: First Loop");
				timeWarp.warpRates [i] = (float)Math.Pow (10, i);
			}

			print ("WarpUnlocker: Done with first loop");
			foreach (CelestialBody iCelestialBody in FlightGlobals.Bodies) 
			{
				print ("WarpUnlocker: Second Loop");
				for (int i = 0; i < iCelestialBody.timeWarpAltitudeLimits.Length; i++)
				{
					print ("WarpUnlocker: Inner Loop");
					iCelestialBody.timeWarpAltitudeLimits [i] = 0;
				}
			}
			print ("WarpUnlocker: Done!");

		}

	}

}

 

And finally, I don't know exactly what " One possible cause, given you say the real mod works, is that you're targetting the wrong version of .net it needs to be version 3.5. " means. I mean, I know it means that I need to target .net version 3.5 but I have no idea how to do that in Monodevelop. I found the string " <package id="Xamarin.Forms" version="2.2..31" targetFramework="portable-net45+win+wp80" /> " in a file named packages.config and changed it to " <package id="Xamarin.Forms" version="2.2..31" targetFramework="portable-net35+win+wp80" /> " and that didn't cause any compile errors, but it also didn't make the mod work.

Share this post


Link to post
Share on other sites
7 minutes ago, 5thHorseman said:

Here's the output_log.txt

Well, it looks like this is the significant error though there isn't any obvious link to your mod:

FileNotFoundException: Could not load file or assembly 'System.Collections, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.

This is happening at the beginning of the flight scene, presumably when KSP tries to actually create your KSPAddon.

9 minutes ago, 5thHorseman said:

And finally, I don't know exactly what...

That is basically, exactly what I meant though you will probably need to use whatever UI there is inside MonoDevelop to make sure the string gets set to the correct value.  I use Visual Studio so it is probably a bit different but, in that you right click on the "project" in the solution explorer and hit "properties" to get the general project options where this is set.

Share this post


Link to post
Share on other sites
11 hours ago, JoePatrick1 said:

I am trying to add a custom category for my mod in the VAB/SPH but I can't get it to work. Here is what I have, please tell me I have made a stupid mistake that is easily solved. Worth noting KBParts.Count is 12 and for some reason when I format as code 'if(KBParts.Count > 0)' is showing as 'if(KBParts.Count > )'

It looks correct, however I see nothing that will refresh the list (IIRC, the stock event doesn't add the buttons unless you actually reset the list). Have you tried switching to a different category and then back to Filter by Function?

Realchute has a nice example (FE deals with things far too abstract/invasive to use as an example -.-)

Edited by Crzyrndm

Share this post


Link to post
Share on other sites

Hello. I'm not really sure where to ask this, but here goes. I want to use an IVA mod to replace all the IVA's for the other cockpit mods I downloaded. Can anybody point me in the right direction to help me get started?

Share this post


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