One of the reasons why Kerbal Space Program is so popular is the wide array of custom parts and mods that the community has put together. If you get tired of building rockets using the built-in parts, you can download a pack of additional components and build more complicated ones. On top of this, you can download mods that add extra behavior to the game, as we discussed previously in Chapter 10 .
If you’re just using other people’s mods, you’re missing out on the fun of creating your own. In this chapter, you’ll learn how to create and add an entirely new part to Kerbal Space Program, and then learn how to write code that extends the behavior of the game.
Rockets are composed of parts . A part is composed of at least two elements:
To make a custom part, you need to create both of these files and then place them in a folder that the game will look inside at startup.
Creating a text file is easy — all you need is a text editor, like Notepad, TextMate, or emacs. Creating a 3D model is quite a bit trickier: you need a 3D model editor, as well as the knowledge of how to use it.
While we don’t have the space to teach you how to use a 3D modeling program from start to finish — we’d need a whole book for that — we can teach you how to use a specific 3D modeling program to create a specific part.
So, to get you started on the road to modding, we’ll introduce Blender , a free and open source modeling tool. We won’t teach all of Blender’s functionality; instead, we’ll teach you just enough to help you make a custom fuel tank, shown in Figure 13-1 .
Kerbal Space Program’s engine, Unity , supports 3D models from pretty much any 3D modeling tool you can name. If you’re already familiar with 3D modeling tools (be it Blender or something else), you can skip this whole section and go straight to “Preparing the Part in Unity” .
If you don’t already have Blender installed, you can get it for free from http://www.blender3d.com . Follow the instructions on the website to download a copy and install it on your computer. Once you have it, start it up.
When you launch Blender, by default you’ll see a scene that contains three objects: a cube, a camera, and a light (see Figure 13-2 ).
We’ll start by removing all of the objects and replacing them with a cylinder. We’ll then start modifying that cylinder to make it look more like a fuel tank; finally, we’ll add a texture to it and then prepare it for use in-game.
One unit in Blender is equal to 1.25 meters in Kerbal Space Program.
If the UV editor window doesn’t contain shapes that look at least similar to Figure 13-14 , your seams are probably not correct — run through the last several steps again.
NiftyTank
, make the width and height 1024 px, and set the Generated Type to Color Grid (see Figure 13-16
).
It’s common to want to make small changes to your texture and see how they look on the model. If you save your image, and then press Alt-R (Option-R on OS X) while the mouse cursor is in the UV Editor pane in Blender, the image will be reloaded and the updated texture will be applied to your object.
You’re all done! When you’re happy with your model, save the file as NiftyTank.blend .
Once you’re done modeling your part, you need to prepare the object for use in the game. You do so using Unity, which is what Kerbal Space Program uses as its game engine. You use Unity to define certain pieces of information, such as the part’s collision shape.
As we just mentioned, to prepare your parts for use in the game, you use Unity, the 3D game engine that powers Kerbal Space Program. You can download Unity from http://www.unity3d.com .
Unity comes in both free and paid versions. The free version is all you need to make mods for Kerbal Space Program.
In addition to Unity, you also need to download a collection of tools from Squad, called the Part Tools . The Part Tools are used to export your processed parts into files that Kerbal Space Program can load.
To prepare your part, follow these steps:
MBM isn’t the only texture format you can use. Feel free to play around with others.
If you go to the folder that you made, you’ll find model.mu and NiftyTank.mbm (see Figure 13-30 ).
You’ve now created two of the three files that this part needs to work: the .mu file contains the mesh, and the .mbm file is the texture. There’s one last thing to make: the .cfg file that describes to the game how the part works.
The config file contains all of the information that Kerbal Space Program uses to put your part in the game. This info ranges from the name of the part, to its mass, its resources, and what modules the part uses to define its behavior. (We’ll be talking about modules in more detail in “Creating a Module” .)
The configuration file format consists of a sequence of nested ConfigNode,
each of which consists of a label, and contains zero or more key-value pairs in curly braces. While the most commonly seen node is the PART
node, there is no restriction as to what nodes can be called, which allows mods to use their own node types as appropriate. As we will see in this chapter, ConfigNodes can also be nested, and even modified after creation, which we’ll discuss in more detail in “Module Manager”
.
The config file also defines important elements like where the attachment points for the parts are, and how the part can be connected to other parts.
To get started, use a text editor (Notepad, TextMate, Sublime Text, emacs, vim, etc.) to create a new file called Part.cfg , and place it next to model.mu and NiftyTank.mbm . Put the following text in it:
PART { // Internal name, not shown to the player name = niftyTank // What kind of part this is (leave as Part in most cases) module = Part // Who made this part? author = Jon Manning // The model file to use mesh = model.mu // How to scale this part (1.0 = original scale, <1.0 = shrink, >1.0 = grow) scale = 1.0 // Top node is positioned -0.75 units below origin, angled down, normal size // (the fuel tank is 1.5 units tall, and centered on the origin) node_stack_top = 0.0, -0.75, 0.0, 0.0, -1.0, 0.0, 1 // Bottom node is positioned 0.75 units above origin, angled up, normal size node_stack_bottom = 0.0, 0.75, 0.0, 0.0, 1.0, 0.0, 1 // Attachment rules: stack, srfAttach, allowStack, allowSrfAttach, // allowCollision attachRules = 1,1,1,1,0 // The technology you need to research in R&D to get this part TechRequired = basicRocketry // How much this part costs to add to your rocket cost = 450 // Which category you can find the part in category = Propulsion // The name of the part title = Nifty Tank // The "manufacturer" of the part manufacturer = O'Reilly Media // The description of this part - no line breaks! description = This is a pretty nifty little fuel tank, if I say so myself. // Physics properties: mass = 0.25 dragModelType = default maximum_drag = 0.2 minimum_drag = 0.3 angularDrag = 2 crashTolerance = 6 maxTemp = 2900 breakingForce = 50 breakingTorque = 50 // The resources that this part contains: liquid fuel, and oxidizer // (Most liquid engines burn 0.9 liquid fuel for every 1.1 oxidizer you // burn, so include them in this ratio) RESOURCE { name = LiquidFuel amount = 90 maxAmount = 90 } RESOURCE { name = Oxidizer amount = 110 maxAmount = 110 } }
node_stack_top
and node_stack_bottom
are the names of the two “stack” attachment points.
This allows it to be part of the stack. You can also specify node_stack_attach
for an attachment point that’s off to the side.
The numbers you provide for the stack attachment points are, in order, its position x , position y , position z , normal x , normal y , normal z , and scale.
Once you’ve written your config file, it’s time to add the part to the game!
A module is a chunk of code that parts use to define their behavior. Modules make up a large percentage of the code in Kerbal Space Program: engines are modules, fuel tanks are modules, and landing gears are modules. When you’re creating a part, the role it plays in the game is defined by the modules that you use.
You can write your own modules for use in Kerbal Space Program. To do this, you write code in C# and create a .dll file containing all of your code. This .dll file is then copied into Kerbal Space Program, which loads it at startup. The code inside this module is only used when your vessel has a part that makes use of the module. This is why, for example, your ship only has access to the functionality of MechJeb when you have a MechJeb part attached to it.
It really helps to know at least the basics of programming to make modules for Kerbal Space Program. Specifically, we’ll be programming this module in C#. There are many excellent resources out there to learn the language; we like Alex Okita’s Learning C# Programming with Unity 3D (CRC Press).
To get started, we’ll create a module that self-destructs when your vessel reaches a certain altitude. This module will need to be attached to a part in order for it to apply to your ship, which means that we’ll then add the module to the NiftyTank part that we created in “Parts” .
To create the module’s .dll file, you’ll need a tool to actually compile the code for you. Fortunately, if you’ve got Unity installed, you already have everything you need. Unity comes with MonoDevelop, an IDE that lets you write C#.
MonoDevelop isn’t the only tool you can use. If you’re using Windows, you can also get a free copy of Microsoft Visual Studio Community.
In this book, we’re using MonoDevelop for a couple of reasons:
Let’s get started by creating the project, and setting it up:
Your project now has access to Kerbal Space Program’s code. It’s time to write some code of your own!
To define a module, you create a subclass of the PartModule
class. Inside this class, you provide your own functionality and data. There are three main things that you care about when writing a
module: fields
, events
, and actions
.
A field is a piece of data that’s stored in the part. Fields can be numbers, pieces of text, on/off values, or other kinds of data. Fields can optionally be exposed to the player to view or modify.
Actions are similar to events, except that they’re triggered by the game as part of a group of other actions. The best example of this is when you define an action group in the editor: when you trigger the Abort action group by pressing backspace, all parts that have a module with an action in that action group run their code.
In addition to fields, events, and actions, your code can also override certain important functions that let you respond to the changing state of the game. For example, override the OnUpdate
method to provide a method that’s run every frame:
using System; namespace TheKerbalBook { public class SelfDestruct : PartModule { // The altitude at which we'll self destruct. [UI_FloatRange(minValue = 500f, maxValue=100000f, stepIncrement=1000f)] [KSPField(guiName="Altitude", guiActive=true, isPersistant=true)] float altitudeThreshold = 10000; // Whether or not automatic self-destruct is turned on. [UI_Toggle] [KSPField (guiName="Destruct", guiActive=true, isPersistant=true)] bool selfDestructEnabled = true; // Called every frame. public override void OnUpdate() { // If self-destruct is enabled, and the altitude of // the vessel that this part is attached to is over // the altitude threshold (defined above), then // self destruct if (vessel.altitude > altitudeThreshold && selfDestructEnabled) { PerformSelfDestruct(); } base.OnUpdate(); } // Adds an action that can be added to an action group in the // editor. [KSPAction("Self Destruct")] public void PerformDestructAction(KSPActionParam param) { PerformSelfDestruct(); } // Adds a button to the right-click menu in the editor. This // function is also called by the PerformDestructAction and the // OnUpdate functions (defined above) [KSPEvent(active = true, guiActive = true, guiName = "Self Destruct")] public void PerformSelfDestruct() { // Kaboom! This will destroy this specific part, leaving the // rest alone. part.explode(); } } }
Your code will now be loaded when the game starts up. There’s one last thing left to do: add the module to the part. This will make the NiftyTank, and only the NiftyTank, have the self-destruct feature:
MODULE
section near the end:RESOURCE { name = Oxidizer amount = 110 maxAmount = 110 } MODULE { name = SelfDestruct } }
This section describes Module Manager (MM), a mod by Ialdabaoth (creator) and Sarbian (maintainer) that lets you change how parts are loaded by Kerbal Space Program. A complete description of parts and all their modules is beyond the scope of this book, but by looking at the files in the subdirectories of the Kerbal Space Program/GameData/Squad/Parts folder on your machine you can find most of the stock parts that ship with the game.
If you install any mod at all, there’s an excellent chance it will come with Module Manager. While it’s not necessary to understand MM in order to use and configure mods, it does provide a powerful way to alter the game and allows you to write many mods with no prior coding experience necessary. If you’re playing with mods, there’s a chance you’ve already got Module Manager installed; if not, you can install it easily using the CKAN (refer back to “Installing Mods Using the CKAN” for details).
The reason why Module Manager is so useful is that it allows you to alter existing parts and configuration for the game. For example, we may wish to alter the mass of the Mk1-2 pod to be 4.3675 tons (the same mass as the real-world Apollo command module). We can do this by placing the following into a .cfg file in your GameData directory containing the following:
@PART[Mark1-2Pod] { @mass = 4.3675 }
This code looks very similar to how we would define a new part, except the at-signs indicate we wish to modify an existing part or attribute. By default, Module Manager will search for a part with the name specified in square brackets; however, as we’ll see in a moment, there are other ways to select parts.
A great many mods for the game are written entirely using Module Manager, as it can not only define new parts and change existing ones, but also place them in the tech tree, alter parameters for other mods, and generally allow you to configure everything .
If you have Module Manager installed, you can start KSP with the
-nyan-nyan
command-line switch for an even better loading screen.
Module Manager supports a number of basic operations.
The most commonly seen is the @
prefix, which changes existing values,
as shown in the previous Mark1-2Pod example. However, the @
prefix does not
create new values. This can be used to our advantage, as it ensures that Module Manager won’t create a part that isn’t loaded. However, when you are changing values within a part, it’s generally safer to use the %
prefix, which creates the attribute
if it does not already exist:
@PART[Mark1-2Pod] { @mass = 4.3675 // Does nothing if the part had no mass %cost = 10000 // Creates the 'cost' field, even if previously absent }
Note that if we didn’t use a prefix at all, Module Manager would add the field to our ConfigNode:
@PART[Mark1-2Pod] { mass = 4.3675 // Uh oh, our pod now has mass *twice*. }
Module Manager also allows you to delete nodes, which can be useful when you are performing complex changes, including removing behaviors or functionality you may not like. Note that when removing both simple attributes and larger modules, you still need to include a value or block (curly braces) for valid syntax, even though the values themselves are ignored:
@PART[Mark1-2Pod] { !ContrabandSandwich = DELETE // No contraband sandwiches here!
!MODULE[ModuleReactionWheel] // Remove the reaction wheel { } }
Finally, you can clone
nodes with the +
operation.
This is particularly useful for making a new part based on an existing part:
+PART[Mark1-2Pod] {
// We need to change the part name, otherwise we'll end up // with duplicate parts!
%name = ElectricPod
// Human visible title %title = Electric Pod
%description = The Electric Pod is just like the Mk1-2 pod, but all the reaction wheel and monopropellant space has been filled with batteries!
!MODULE[ModuleReactionWheel] { }
!RESOURCE[MonoPropellant] { }
// Change existing resource limits.
@RESOURCE[ElectricCharge] { %amount = 9001 %maxAmount = 9001 } }
When modding, at some point you’ll likely want to find all the parts that have a particular attribute and change them in some way. For example, with a life-support mod you may wish to find all parts that have a crew capacity and add food, water, and oxygen supplies to them.
Module Manager supports a :HAS[]
syntax for selecting parts,
allowing you to select parts based upon the presence of an attribute or module. For example, if we wanted to select all single-person pods and passenger compartments, we could do this:
@PART[*]:HAS[#CrewCapacity[1]] { }
It’s possible to provide multiple :HAS[]
conditions. We can select single-person pods (but not passenger compartments) by looking for the ModuleCommand
module (designated with an @
):
@PART[*]:HAS[#CrewCapacity[1],@MODULE[ModuleCommand]] { }
Likewise, we could select all single-person passenger compartments by looking for the absence of the same module:
@PART[*]:HAS[#CrewCapacity[1],!MODULE[ModuleCommand]] { }
One of the great uses for this technique is being able to add a module if it doesn’t already exist. For example, if we wanted to add MechJeb to all command parts that didn’t already have it, we can do so!
// Add MechJeb to all command-modules that don't already have it. @PART[*]:HAS[@MODULE[ModuleCommand],!MODULE[MechJebCore]] { MODULE { name = MechJebCore } }
When you are applying tweaks using Module Manager, it’s important for things to run in the right order, especially if you wish to make adjustments to an existing mod.
Module Manager allows for three special ordering directives: :BEFORE[]
, :FOR[]
, and :AFTER[]
, which allow change ordering to be more precisely controlled.
By marking a stanza with :FOR[]
, we can indicate it’s for a particular mod:
@PART[Mark1-2Pod]:FOR[KerbalBook] { @mass = 4.3675 }
Module Manager will execute all the stanzas of a given mod together, even if they’re spread among different files. This makes it possible for other mods to ensure their work is done before or after that mod’s changes are made. For this reason, it’s considered best practice to always
tag your stanzas with :FOR[]
directives if you’re going to distribute them, so other mods can ensure they can run before or after your own changes.
Since a :FOR[]
tag will signal to Module Manager that a given mod is installed, you should make sure that your mod-name is unique
to your mod. This will allow other mods to better integrate with yours (discussed momentarily), and also make sure you don’t interfere with any other mod’s compatibility modes.
Module Manger will run a pass for every assembly and top-level folder in the GameData
directory, so using a :FOR[]
with the same name as your mod’s directory name is strongly
recommended.
For example, if we wanted to adjust the antenna properties added by RemoteTech, we need to run after RemoteTech; otherwise, we’ll have no antenna module to change:
@PART[probeCoreOcto]:AFTER[RemoteTech] { @MODULE[ModuleRTAntennaPassive] { // Boost the Octo's in-built antenna to 30k range. %OmniRange = 30000 } }
In the same way, it’s also possible to run :BEFORE[RemoteTech]
(or any other mod), or :NEEDS[RemoteTech]
if you just need RemoteTech to be installed but aren’t concerned about the ordering. A useful trick is to run code before your own
mod, if there’s initialization work that needs to occur before the main changes are executed.
Module Manager considers mod names to be case-insensitive, so KerbalBook
is the same as KERBALBOOK
.
Module Manager also allows
stanzas to be tagged as :FIRST
or :FINAL
. These don’t take any mod names but instead run before or after all other Module Manager passes. If you’re tweaking your own game, then using :FINAL
is an easy way to make sure your changes happen after everything else (and hence take priority), but its use is discouraged in release mods, as it can prevent others from effectively building on your work, including providing compatibility between mods.
If you want a quick reference to the ordering of ModuleManager passes, they are:
:FIRST
:BEFORE[]
,:FOR[]
,:AFTER[]
for each mod (in alphabetical mod order):FINAL
If a mod doesn’t exist, then any :BEFORE[]
, :AFTER[]
, or :NEEDS[]
directives referring to that mod will not
be executed, which is why it’s important not to accidentally add a directory, assembly, or :FOR[]
which creates a pass by accident.
One popular use of Module Manager is to tweak how science experiments work. For example, a thermometer’s readings are simple enough (a temperature) that they should be fully transmissible, whereas Mystery Goo represents a material sample that might have to be returned home to be properly studied.
Tweaking the transmit values requires quite a bit of Module Manager syntax, but it means we can adjust experiments even if mods have added new parts with them! Here’s how we can do that for the temperature scan:
@PART[*]:HAS[@MODULE[ModuleScienceExperiment] :HAS[#experimentID[temperatureScan]]]:FINAL { @MODULE[ModuleScienceExperiment]:HAS[#experimentID[temperatureScan]] { @xmitDataScalar = 1.0 } }
The first line of the preceding code — that is, everything up to the curly brace ({
) needs to be on the same line. We’ve had to break it into two lines here because it didn’t fit on the page, but when it appears in a file, it has to be in a single line.
While this code looks pretty scary, it’s not too hard to understand once we break it down into pieces. These changes apply to all parts (@PART[*]
) that run science
experiments (:HAS[@MODULE[ModuleScienceExperiment]...
) that measure temperature (#experimentID[temperatureScan]]]
). Additionally, we then indicate that we want to run them after all other parts have been configured (:FINAL
).
Once we’ve found a part that matches what we’re after, we use Module Manager to find the module describing the temperature experiment (@MODULE[ModuleScienceExperiment]:HAS[#experimentID[temperatureScan]]
), and then modify the transmit value to send the full science value (@xmitDataScalar = 1.0
).
This may seem like a lot of work, but we’ve purposely chosen a more complex example to show off the power of Module Manager to select and manipulate parts.
We could
have just used @PART[*]
without any :HAS
blocks at all and this still would have worked, as our inner block is specifically checking for the right experiment. The advantage of the long selector is that it’s easier for us to modify the code in the future in case we want to make other changes to temperature-scanning parts (but not necessarily to the science experiment itself), such as adjusting their price or ensuring they all have the same mass.
When you mod KSP, you’re opening a huge amount of possibility.
In this chapter, we’ve only had space to cover a fraction of what’s available to you when modding KSP. To learn more about what’s available, check out the community documentation , as well as the Add-on Development forum and TaranisElsu’s excellent example projects .
In the next chapter, we’ll move beyond the world of software and look at what you can do to add real-world hardware to the game.