Skip to content

Writing plugins for RasterPropMonitor

Eugene Medvedev edited this page Jun 14, 2014 · 14 revisions

Having struggled enough with Squad's silly plugin loader, I know it can be painful to link to a foreign plugin in KSP. The problem with integrating multiple plugins in KSP is that while normally, you would just reference a plugin and call it's member classes directly, KSP plugin loader will reject your plugin upon loading if the referenced plugin is not already loaded. You can ensure your plugin loads later than the plugin you're referencing, because KSP loads them in alphabetical order, but then, if the referenced plugin is not present, yours won't load at all anyway, which is in many situations unacceptable. This problem can be solved using reflection and delegate functions, but the solution is quite cumbersome. Well, the trick with RPM API is that:

  • You don't have to hard link to RPM. You don't need to reference RPM's DLL. You don't stop working if RPM is not installed either and you don't need a separate assembly.
  • You don't need to know anything about reflection, either. It's enough that RPM knows enough about it.

Interfacing to RPM is done by creating classes that contain methods with specific signatures -- that is, which take a certain list of parameters in a specific order, and return specific things -- and writing RPM configuration files which tell RPM what the names of all these things are. RPM will then take care of instantiating those classes as appropriate and calling the methods you name. These classes can be part of your own assembly, and are thus allowed to directly manipulate the internals of your plugin that otherwise does something independently. As long as RPM API doesn't change, which isn't expected to happen, you can expect to continue working with any conceivable future version of RPM, as long as one exists, with no changes.

The mechanism is in almost all cases the same:

		PAGE
		{
                            ...
			SOMETHINGANDLER
			{
				name = YourClassName
				method = TheMethodToCall
			}
		}

When seeing such a configuration block, RasterPropMonitor (except where explicitly stated otherwise) takes care of locating your class, creating an instance of it and attaching it to a game object in KSP. (In almost all cases, an IVA prop). In all cases, the *HANDLER {} block is passed to the module as if it were a MODULE {} block in a regular prop configuration file. Certain reserved words contain parameters for RasterPropMonitor, telling it about other interesting methods to call on that class when something happens (for example, the user presses an RPM button) or is needed to display a screen. The full list differs depending on the type of handler and what it's supposed to do. The classes are perfectly regular classes otherwise, and as long as they respond to RPM's calls, they can do whatever they please.

The entire mechanism is used internally for much of RPM's own more advanced functions, so you can see examples in RPM's own code -- every handler works as one, but JSIFlightLog.cs is particularly instructive, as it's commented throughout specifically for this purpose. The particular things that can be plugged into are:

  • Page handlers -- Modules that tell RPM what to print on screen.
  • Background handlers -- Modules that get an RPM screen to draw graphics on.
  • Action handlers -- Modules that can be triggered by RPM-driven switches to perform an action of any kind and report any kind of on/off state.
  • Variable handlers -- Modules that add extra variables that RPM pages can use.