Jump to content

Vessel Modules Discussion


Recommended Posts

I haven't seen any proper discussion of this (very useful) new type of plugin that was introduced with KSP 1.0 and feel they need a bit more attention. They're not hugely different from other plugin types but the sheer lack of information slows things down so hopefully this will be helpful ;)

Compared the plugin types

  • Part Module: One set of modules per part. Number of modules for a part is set in part configuration file. Active during initial loading (do try not to...), editor, and flight scenes. Save persistence of variables using the KSPField attribute with the option isPersistant set true
  • KSP Addon: Single instance. Only one instance of the plugin object running, limited to either a single scene or all scenes
  • Scenario Module: Single instance per save, used for storing/retrieving persistent data that isn't associated with a part (? I haven't used this one so I don't know much about it)
  • Vessel Module: One instance per physics enabled vessel object. Only active in the flight scene. No direct access to the persistence file.

Vessel Modules are closer to the KSP Addon style plugin in my opinion, the main difference being that it's one instance per loaded vessel rather than per scene. Otherwise VesselModule also inherits directly from MonoBehaviour and has no behaviour of its own other than the startup mechanism.

Using Vessel Modules

Inherit from VesselModule to have your class added to every vessel as it becomes physics enabled

class DerivedVesselModule : VesselModule

Classes inheriting from VesselModule have access to all of MonoBehaviour's functions (Awake, Start, OnDestroy, OnGUI, Update, FixedUpdate, etc.)

Getting a vessel module object from a vessel:

vesselObject.GetComponents<VesselModule>(); // a list of all classes inheriting from VesselModule attached to the vessel
vesselObject.GetComponent<DerivedVesselModule>(); // the instance of your derived class attached to the vessel

Getting the vessel object from the VesselModule

vesselModule.GetComponent<Vessel>();

Tips and notes on using Vessel Modules

  • Don't keep a reference to the vessel module in another class unless you can guarantee the other class will be destroyed first or will not attemt to call any function after the module is destroyed (ie. not part modules or KSP addons). Instead keep a static dictionary of the vessels and their associated vessel modules in the class deriving from VesselModule (credit to ferram4)
  • If your VesselModule is tracking the output of some part modules, you can tell when a part module separated from the original vessel because it will show up in a new vessel module. Use this to make sure the parts are attributed to the correct vessel instead of responding to various GameEvents or watching part.vessel for changes.
  • The first frame of Fixed Update when switching to the scene is called before the Flight scene setup completes. Leads to lots of nullrefs/NaN/other Kracken bait
  • ...?

Plugins using VesselModules

Examples are always helpful ;)

  • Modular Flight Integrator: link
  • Ferram Aerospace Research: link1 link2
  • Pilot Assistant: link
  • Symmetric Flameout: link
  • Real Fuels (ullage branch): link
  • Solver Engines: link
  • Others...?

Edited by Crzyrndm
Link to comment
Share on other sites

A couple things to add to this:

VesselModules inherit MonoBehavior so some of the familiar methods are available.

Known to work: Awake(), Start(), OnDestroy(), OnGUI(), Update(), FixedUpdate()

Known to NOT work: OnSave(), OnLoad()

This is the biggest limitation of VesselModule, there is no persistence with the .sfs file, you have to save/load data manually or hook into a PartModule to persist data.

To Use:

class DerivedVesselModule : VesselModule
{
//stuff here
}

KSP will do the rest and add a single instance of your DerivedVesselModule class to every vessel in the game when said vessel is loaded into the flight scene.

D.

Link to comment
Share on other sites

If that is true, then this is much less useful to me :(

I know, I've been trying to find a way around this myself.

The best idea I've been able to come up with so far is to hook into the GameEvents.Load/Save methods to read/write data.

I have not tested this, but as I understand it those events pass a configNode that ties into the save file, so if you added a master node "MyModNode", then each vessel as a sub-node (probably with Vessel.ID), I think that would work?

Note I have not tested this in any way, one of the issues I have already thought of is how to tell the difference between a newly spawned vessel on the pad, and a vessel that has just undocked? In both cases the vessel will not have an entry in the MyModNode confignode so I'm not sure how to handle that yet.

D.

edit: I just had a thought on how to do this, I should have something to post tomorrow that would make this work.

Edited by Diazo
Link to comment
Share on other sites

Nice list, I was trying to figure out what type of mod I needed to modify recovery values, and this list really helped. It'd be nice to update with a short mention of how each is accomplished, i.e. inheriting from :PartModule or "a KSP Addon is simply a class marked with the attribute [KSPAddon(...)] and inherits from MonoBehavior. Note even though this doesn't inherit from anything KSP specific, there's static classes such as GameEvents that expose KSP specific hooks into the game.

This is a good example of a KSPAddon: https://github.com/magico13/StageRecovery/blob/master/StageRecovery/StageRecovery.cs

Note wiring functions up to events so that the Addon can hook and have an opportunity to modify game behaviors:


//Fired when the mod loads each scene
public void Start()
{
if (Settings.instance != null)
Settings.instance.gui.hideAll();


//If we're in the MainMenu, don't do anything
if (forbiddenScenes.Contains(HighLogic.LoadedScene))
return;


//If the event hasn't been added yet, run this code (adds the event and the stock button)
if (!eventAdded)
{
GameEvents.onGameSceneLoadRequested.Add(GameSceneLoadEvent);
//Add the VesselDestroyEvent to the listeners
GameEvents.onVesselDestroy.Add(VesselDestroyEvent);
//Add the event that listens for unloads (for removing launch clamps)
GameEvents.onVesselGoOnRails.Add(VesselUnloadEvent);
//GameEvents..Add(DecoupleEvent);
//If Blizzy's toolbar isn't available, use the stock one
// if (!ToolbarManager.ToolbarAvailable)
GameEvents.onGUIApplicationLauncherReady.Add(Settings.instance.gui.OnGUIAppLauncherReady);
//Set the eventAdded flag to true so this code doesn't run again
eventAdded = true;
}
....

GameEvents are a bit funky data structure for exposing events. Here's how you can determine what types you need in your event handler.

Type this in Visual Studio:


GameEvents.onVesselRecoveryProcessing.Add(

And then mouse over .Add( or hit Ctrl+K+P to popup parameter info, you should see the parameter type of


EventData<ProtoVessel,MissionRecoveryDialog,float>.OnEvent

If you're familiar with Func<X,Y,Z> generic delegates, this is essentially the same thing.

The above types in angle brackets `<ProtoVessel,MissionRecoveryDialog,float>` tells you that you need to declare a function with those three parameters:


void OnVesselRecoveryProcessing(ProtoVessel vessel, MissionRecoveryDialog recoveryDialog, float unknown)
{

}

The parameter types are self explanitory sometimes, but a primitive type like float is a bit of a mystery. If the documentation doesn't reveal anything useful, then probably just using `print(` to print to Debug window values as the event is triggered is best way to try and guess the meaning of the parameter.

https://anatid.github.io/XML-Documentation-for-the-KSP-API/class_game_events.html#a17641c8a2f9a01e61eec763737eb7b89

Once you've declared your function, then pass the function name to .Add. When you reference a function by name without parenthesis then you are passing it as a delegate instead of executing it. If you are familiar with function pointers in other languages, this is a similar concept.

RIGHT:


GameEvents.onVesselRecoveryProcessing.Add( OnVesselRecoveryProcessing );

WRONG:


GameEvents.onVesselRecoveryProcessing.Add( OnVesselRecoveryProcessing() );

Edited by AaronLS
Link to comment
Share on other sites

You may not have noticed but this was specifically about VesselModule type plugins, for which there was no information unless you happened to stumble upon them in one of about 4 plugins and do your own testing to ascertain the behaviour. The only reason the other plugin types are mentioned is as a comparison, there are hundreds of examples of PartModules and MonoBehaviour/KSPAddon out there. If you look at all you can't miss them.

tl;dr

Nice helpful post, but the context is somewhat lacking...

Link to comment
Share on other sites

Yes, I did notice that, but I wanted to mention that more than anything that list was the most valuable. Yes, there may be many example of each, but if you aren't even aware of the different mod types they are very hard to find. Any google of "ksp add on" turns up pages listing part modules. This is the first time I've seen the different types all listed together and distinguished as to what their purpose is. I had seen this post when you first posted it, and today I was wanting to mod the recovery process and was asking myself "Is this even possible? Is there a way to mod the entire game? I'm sure I saw someone mention that somewhere." I actually thought I remembered you refer to it as an "Add On" but every google of "ksp add on" turns up just generic pages dealing with any type of KSP mod, which are mostly PartModules. The entire first page of results are just pages that list mods. I began to question whether I was mistaken in what I had remembered, but I kept hunting around and googling and found this post again.

Many of the getting started examples and tutorials jump right into things like "Let's make an engine" that is so specific that I found them of virtually no use. I got tired of trudging through that and I've been learning more from looking through code on github than anything else.

I just thought I'd build upon that and expand slightly deeper to emphasize exactly what a KSP Add on is. I realize that wasn't the original purpose of the post. But the list was the only comprehensive list I've seen and thought I'd build upon that with just a little bit more concrete information. I find that kind of detailed information is helpful in selecting what approach to take in anything programming related. Conceptual descriptions help a little bit, but seeing just a couple examples helps make it more concrete and that decision process has alot more to go on.

Link to comment
Share on other sites

  • 5 years later...
On 6/22/2015 at 5:45 PM, Diazo said:

Known to NOT work: OnSave(), OnLoad()

This is the biggest limitation of VesselModule, there is no persistence with the .sfs file, you have to save/load data manually or hook into a PartModule to persist data.

 

What exavtly do you mean by "Known to NOT work"?  OnStart and OnLoad are called durring runtime and [KSPField(isPersistant = true)] seems to save variables (KSP 1.8.1)

Perhaps they fixed it?

Edited by FreeThinker
Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

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