Parts Pack Production Procedure

From KSP 2 Modding Wiki
Revision as of 19:41, 8 March 2024 by Munix (talk | contribs) (→‎Material setup)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The aim of this tutorial is to guide you through the process of creating your first part mod for Kerbal Space Program 2. We will go over everything from creating the part's mesh and textures to setting up the part in Unity to be bundled into a KSP2 mod.

The way this tutorial will be structured is as a succession of steps which may link to other tutorials on this wiki, do not hesitate to keep this main page open while perusing the other tutorials. We aim at being as comprehensive as possible to enable you to make any part mod, but this page is still work in progress so stuff might be incomplete and/or subject to change in the future.

Magnificent Mesh Modelling (Creating the part asset)

The first step in your part mod creation journey is to create the part's "3D asset", meaning its 3D mesh, textures and eventual animations. You can use any software you're comfortable with to do so but here are some guides for some specific software if you desire:

  1. Modeling the mesh in Blender
  2. Texturing the mesh in Substance 3D Painter

Here are some resources that can be useful for modelling and texturing, regardless of the software you're using:

Part Pack Prep (Basic Unity part mod project setup)

Now that you have created a model and textures for your part, the next step is to set up a Unity project that will be used to configure your part and build the asset bundles that will contain your mod's contents.

  1. Creating the project: Follow the Setting up Unity tutorial to create and set up a project for part modding.
  2. Parts Pack folder: Under Assets, create a folder (R-Click Assets: Create > Folder) and name it the same as your parts pack mod. If your mod is called My Awesome Mod then this would be Assets\MyAwesomeMod.
  3. Materials folder: Inside your parts pack folder create a folder called Materials. You’ll be storing the textures and materials you need there. E.g., Assets\MyAwesomeMod\Materials. This is just to aid in organization.
  4. Parts folder: Inside your parts pack folder create a folder called Parts. You’ll be storing the part meshes and related things there. E.g., Assets\MyAwesomeMod\Parts. You can have whatever organization you like here, so if you want to group some parts you might create group folders within Parts (e.g., Methalox Engines, Nuclear Engines, Ion Engines, etc.). This is just to aid in organization and is optional.
  5. Plugin Folder and Content: In your Unity project's Assets\plugin_template folder create a localizations folder. NOTE! This is currently required to be exactly this – localizations (plural), not localization (singular). This will be where you put the localization file.
    1. Create Localization file: Localization files are CSV files following a particular format. These must have lines ending with LF not LF/NL, and they must reference the same <part_name> you use in the Part Production process below. There are some other restrictions for content, particularly that if you want a string that contains a “,” that string needs to be enclosed in quotes or the comma will mess with how the strings are parsed. These files are where the part’s Title, Subtitle, Manufacturer, and Description are configured. Here’s an example:
      Key,Type,Desc,English,French
      
      Parts/Title/spark_spt100,Text,,SPT-100,SPT-100
      Parts/Subtitle/spark_spt100,Text,,Hall Effect Thruster with Xenon Tank,Moteur à Effet Hall et Réservoir de Xénon
      Parts/Manufacturer/spark_spt100,Text,,"Stellar Plasma-Assisted Rocket Kinetics, inc.","Stellar Plasma-Assisted Rocket Kinetics, inc."
      Parts/Description/spark_spt100,Text,,"The SPT-100 is the pinnacle in tiny (0.625m-class) Ion engines, providing high Isp and low thrust with an integral toroidal xenon tank. Strap this little guy onto a probe core and be sure to bring plenty of electrons because you're in for a long slow ride to anywhere!","Le SPT-100 a le dessus dans la catégorie des très petits (0.625m) moteurs ioniques, avec une haute impulsion spécifique et une poussée faible ainsi qu'un réservoir toroïdal de xénon intégré. Accrochez ce petit gars à vos sondes et assurez-vous d'avoir du stock d'électrons car vous allez aller de partout bien lentement!"
      
      Parts/Title/spark_x3,Text,,X3 NHT,X3 NHT
      Parts/Subtitle/spark_x3,Text,,Three-Channel Nested Hall Effect Thruster,Moteur à Effet Hall à 3 Canaux Concentriques
      Parts/Manufacturer/spark_x3,Text,,"Stellar Plasma-Assisted Rocket Kinetics, inc.","Stellar Plasma-Assisted Rocket Kinetics, inc."
      Parts/Description/spark_x3,Text,,"The SPARK X3 is the pinnacle in small (1.25m-class) Ion engines, providing high Isp and low thrust. Strap this bad boy onto your large probe or small capsule and be sure to bring plenty of electrons because you're in for a long slow ride to anywhere!","Le SPARK X3 a le dessus dans la catégorie des petits (1.25m) moteurs ioniques, avec une haute impulsion spécifique et une poussée faible ainsi qu'un réservoir toroïdal de xénon intégré. Accrochez ce petit gars à vos grandes sondes et assurez-vous d'avoir du stock d'électrons car vous allez aller de partout bien lentement!"

Primary Part Production (Basic part setup)

This part of the tutorial will go over how to create a basic KSP2 part in Unity.

  1. Create Root Part Object: Create an empty game object under your scene (R-click Scene: Game Object > Create Empty). Name this object the same as your part.
    1. Recommended naming scheme: <mod_name>_<part_name>. If your mod is called My Awesome Mod and your part title is My Part, then your part name might be my_awesome_mod_my_part for example. Part names must be unique, though you can have any descriptive title you like (that is done later in Localization). A naming scheme like this helps to prevent naming collisions in case anyone else might make a part they want to call My Part, like yours.
  2. Create Model Object: Create an empty game object under your root part object and name this one model.
  3. Create Part Folder: Create a Part folder named for your part inside your Parts folder. E.g., Assets\MyAwesomeMod\Parts\MyPart, or Assets\MyAwesomeMod\Parts\ThisGroup\MyPart if you’re grouping parts.

Mesh setup

  1. Bring in the Mesh: Drag a copy of your part’s FBX file into the part folder. If you have baked textures for your part that go with the FBX (meaning, they’re based on the UV Unwrap specific to that FBX), then drag those into this same folder along with the FBX.
  2. Create Part Mesh Object: Drag a copy of the part's FBX from the Part folder in Unity to the model object created in step 2. Don’t drag the FBX file from your computer’s files system, you need to use the copy you just placed in step 4. This will create a prefab for your part as a child of the model object.
  3. Unpack Prefab: Right-Click part object: Prefab > Unpack.
  4. Remove Unnecessary Things: Remove any objects that came in with the FBX that you don’t actually need in the game like lights, cameras, empty nodes, etc. If it’s not an actual object you want the game to render, then delete it.
  5. Orient Part: Your model will appear in the Unity scene oriented as you built it in Blender, but this may not be the way you want it to be oriented in the game. If you need changes to the position, rotation, or scale of the part do those now using the Transform panel within the Inspector Window with your part object selected. For example, to flip a part over just give a rotation of 180 in Z, etc.

Material setup

  1. Create the material: Create a material in Unity for each material in Substance Painter (right-click on the project window > Create > Material)
  2. Select the KSP2 Shader: Select all materials. In the Inspector window, in Shader, select KSP > Parts > Paintable.
  3. Apply the textures: For each material, assign the textures to the Albedo, Metallic, Normal, Emissive and Paintable channels.
    1. For Normal channels, click the Fix Now button.
  4. Set properties: Set Metallic/Smoothness Map to 1 and check Use PaintMask for Paint Smoothness.
  5. Apply materials: For each mesh, assign the materials to the corresponding locations. Click on Apply.

Collider setup

  1. Create Collider Object: R-Click mesh object: Create Empty. Name this object col.
  2. Create Collider: In the Inspector window for the col object click “Add Component”. Search for Mesh Collider and pick it. This will create a Mesh Collider component in the col object. Click the arrowhead to the left of it to expand it and see its properties.
    1. Select Mesh: In the Mesh Collider properties select the Mesh you want to use. If your FBX is all one object you can pick that, or you can pick a suitable primitive like cube or cylinder, etc.
    2. Position, Rotation, and Scale: Set the position, rotation, and scale of the mesh to encompass the part. You should see a green mesh represented in the Scene window to help guide you to make sure you’ve got the right position, rotation, and scale.
    3. Convex: Check “Convex”

Core Part Data setup

  1. Add Core Part Data: Select your Root Part Object. In the Inspector Window click “Add Component”. Search for “Core Part Data” and pick that. Open it up and configure as follows:
    1. Part Name: The Part Name needs to be the same as what you’ve used for the Root Part object, i.e., my_awesome_mod_my_part or whatever you used.
    2. Author: Use what you like here, typically your KSP Forum screen name or whatever you go by as your modding author name.
    3. Category: Select an appropriate category for your part.
    4. Family: If you wish to identify a “Family” for your part, this needs to be a particular string. You can find examples in the game’s files, or part JSONS, or ask in the KSP2 Modding Society discord to get this information.
    5. Co Lift, Co Mass, Co Pressure, etc.: These parameters allow you to set the Center of Lift, Center of Mass, Center of Pressure, etc. Adjust these to get the markers in the Unity scene where they should be for your part. Typically, Co Pressure and Co Lift are in the same place.
    6. Fuel Cross Feed: Check if fuel should be able to transit through your part on the way to other parts. Typically set to true, but not always.
    7. Mass: Set this in metric tons, not Kg.
    8. Attach Rules: Check the types of attachment your part should allow. Checking “Stack” or “Srf Attach” will allow your part to attach in a stack or to a surface. Checking “Allow Stack”, “Allow Srf Attach”, etc. will allow other parts to stack attach or surface attach respectively. Currently (?) Allow Collision, Allow Dock, Allow Rotate, and Allow Root have no effect in game (check this).
    9. Attach Nodes: If Stack is checked above, then you need a “top” and a “bottom” node, if Srf Attach is checked above, then you need a “srfAttach” node. Note, node names are case sensitive and having a node is not enough by itself, you do also need the corresponding Attach Rule set true or the node will have no effect. Under Attach Nodes click the + button to add a blank node and configure as needed.
      1. Node ID: “top”, “bottom”, “srfAttach”, etc. (case sensitive!)
      2. Node Type: Select as appropriate. (Stack for Stack, Surface for Surface…)
      3. Attach Method: Select Fixed_Joint for Stack and Hinge_Joint for Surface Attach.
      4. Is Multi Joint: In general set to True for stack attach to help prevent noodle rockets.
      5. Multi Joint Max Joint: Set to 3 if you set Is Multi Joint to true?
      6. Position: Set as appropriate. Should be on the skin or outside of the part where you would expect to find it on your part in the VAB.
      7. Orientation: Set as appropriate. The Orientation vector should be a unit vector (length 1) pointing in the direction of the part that will attach to the node, so pointing away from your part.
      8. Size: Affects rigidity of your part. If your part is connected to another part with the same “size” node, then rigidity will be optimal, and otherwise it will be suboptimal.
      9. Visual Size: Set the same as Size.
      10. Is Resource Crossfeed: Set as needed for this node.
      11. Is Rigid: Set as needed for this node.
      12. Rinse and Repeat: Subsequent nodes created with the + button will inherit settings from the last node made, so this may accelerate the process as you just need to change the Node Id, Position and Orientation for new nodes that are similar to the previous created node.
  2. Add Module_Color: You need this to be able to paint your part with base and accent colors. As above, click Add Component and search for Module Color.
  3. Add Module_Drag: All parts need this. As above, click Add Component and search for Module Color.

Crazy Customization (Adding functionalities to the part)

  1. Add other modules as needed. For example, if your part is an engine you’ll also need:
    1. thrustTransform object: Create an empty game object as a child of the root part and name it thrustTransform.
    2. Throttle VFX Manager: Configure as needed (?). No need to drag anywhere, it just need to be a component for the part.
    3. Flameout VFX Data: Drag this up to the Flameout VFX property in Module_Engine.
    4. Module_Gimbal: Configure details as needed (e.g., Gimbal Range and Gimbal Speed, etc.), then drag this up to the Gimbal property in Module_Engine.
    5. Module_Generator: Configure details as needed, then drag this up to the Alternator property in Module_Engine.
    6. Module_Fairing: Unless you plan for your engine to only ever be on the very first stage (i.e., a big booster), then you probably want it to have a fairing so it can be used in the second stage and above. Figure 3 shows an example for a working fairing from a Size Small (1.25m-class) engine that was created using this process. Shown below is the corresponding example of the PartComponentModule_Fairing portion of the part JSON. As can be seen in Figure 3, the data fields that need to be populated in the Unity Editor include only a subset of what's in the auto-generated JSON. That said, everything the editor needs is in the example below and presenting it this way makes copy/paste possible where unity editor graphic would not allow that.
      Figure 3: Example Fairing Data in Unity Editor
            {
              "Name": "PartComponentModule_Fairing",
              "ComponentType": "KSP.Sim.impl.PartComponentModule_Fairing, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
              "BehaviourType": "KSP.Modules.Module_Fairing, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
              "ModuleData": [
                {
                  "Name": "Data_Fairing",
                  "ModuleType": "KSP.Modules.Module_Fairing, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
                  "DataType": "KSP.Modules.Data_Fairing, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
                  "Data": null,
                  "DataObject": {
                    "$type": "KSP.Modules.Data_Fairing, Assembly-CSharp",
                    "FairingEnabled": {
                      "ContextKey": "FairingEnabled",
                      "storedValue": true
                    },
                    "FairingConstructionType": {
                      "ContextKey": "FairingConstructionType",
                      "storedValue": "CUSTOM"
                    },
                    "FloatingNodeEnabled": {
                      "ContextKey": "FloatingNodeEnabled",
                      "storedValue": true
                    },
                    "Length": {
                      "ContextKey": "Length",
                      "storedValue": -1.0
                    },
                    "DeployType": {
                      "ContextKey": "DeployType",
                      "storedValue": "Clamshellx4"
                    },
                    "EjectionForce": {
                      "ContextKey": "EjectionForce",
                      "storedValue": 100.0
                    },
                    "IsStagingEnabled": {
                      "ContextKey": "IsStagingEnabled",
                      "storedValue": true
                    },
                    "IsDeployed": {
                      "ContextKey": "IsDeployed",
                      "storedValue": false
                    },
                    "FloatingNodeSize": 1.0,
                    "FloatingAttachNodeTag": "bottom",
                    "FloatingNodePosition": {
                      "x": 0.0,
                      "y": 0.0,
                      "z": 0.0
                    },
                    "FloatingNodeDirection": {
                      "x": 0.0,
                      "y": -1.0,
                      "z": 0.0
                    },
                    "FloatingNodeIsMultiJoint": false,
                    "FloatingNodeMultiJointMaxCount": 3,
                    "FloatingNodeMultiJointOffset": 1.0,
                    "FairingNode": "top",
                    "NoseTip": 0.5,
                    "EdgeWarp": 0.02,
                    "AberrantNormalLimit": 45.0,
                    "LocalUpAxis": {
                      "x": 0.0,
                      "y": -1.0,
                      "z": 0.0
                    },
                    "Pivot": {
                      "x": 0.0,
                      "y": 0.0,
                      "z": 0.0
                    },
                    "BaseModelTransformName": "Base",
                    "CapRadius": 0.375,
                    "BaseRadius": 0.625,
                    "CloseRadius": 0.375,
                    "MaxRadius": 6.0,
                    "SnapThreshold": 0.25,
                    "CreateShellColliders": false,
                    "NumberOfCollidersPerCrossSection": 12,
                    "MinHeightRadiusRatio": 0.07,
                    "CrossSectionHeightMin": 0.3,
                    "CrossSectionHeightMax": 1.1,
                    "AerodynamicallyShieldContents": false,
                    "ConeSweepRays": 120,
                    "ConeSweepPrecision": 10.0,
                    "AmountOfCollidersPerArc": 1,
                    "ShouldCapOnAutoGenerate": false,
                    "IsCapped": false,
                    "IsShroud": true,
                    "MassAreaRatio": 0.0,
                    "FairingSideCount": 24,
                    "FairingLengthSnapIncrement": 0.125,
                    "FairingRadiusSnapIncrement": 0.125,
                    "FairingSmoothingAngle": 35.0,
                    "FairingThickness": 0.025,
                    "FairingStartHeight": 0.0,
                    "AllowConstructionTypeChange": true,
                    "AllowFloatingNodeChange": true,
                    "DefaultFairingEnabledToggle": true,
                    "DefaultAutoConstruction": true,
                    "DefaultDeployType": "Shroud",
                    "DefaultFloatingNodeState": true,
                    "LengthEditMinimum": 0.0,
                    "LengthEditMaximum": 0.001,
                    "LengthEditDefault": 1.0,
                    "StageToggleDefault": false,
                    "MaxAutoFairingTargetRadius": -1,
                    "MinAutoFairingTargetRadius": -1,
                    "CrossSections": [],
                    "MassModifierAmount": 0.0,
                    "DragCubeIndex": -1,
                    "ModuleType": "KSP.Modules.Module_Fairing, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
                    "MassModifier": 0.0,
                    "DataType": "KSP.Modules.Data_Fairing, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
                    "IsActiveInStagingProp": {
                      "ContextKey": null,
                      "storedValue": false
                    }
                  }
                }
              ]
            }
      Of the information show above, the parts you will most likely need to customize for your fairing are Base Radius, Cross Section Height Max, and Fairing Thickness - the rest is likely to be the same for all your engines with one other important thing to note. The example above is for an engine that was made in Blender with the nozzle bell facing upwards. If your engine was made with the nozzle bell facing down, then you will need the Local Up Axis to be -1 in Y and you will also need set the Fairing Node to bottom.

Final Flourishes (Final steps)

  1. Apply Options: Select the root part and in the Inspector window near the top on the Prefab line, click the Overrides dropdown and pick Apply All. If this option is not available, then you’ve got nothing you need to do here. Move along, move along.
  2. Save Part JSON: Click Save Part JSON button at the bottom of the Core Part Data module. This will put the resulting part JSON in the Assets folder for your Unity project. You need to do this any time you’ve edited the Core Part Data module (or also a module it depends on?).
  3. Make Prefab: Grab the root part object and drag it to the Unity project Assets folder.
  4. Add Part Icon: Create an icon for your part that the game will use in the parts picker. This needs to be a PNG file with specific dimensions. It should conform to the style used by other parts in the game. However you do this, you need to name the file <part_name>_icon.png, and you need to drag that file into the Assets folder in Unity.
    1. Convert Icon to Sprite: Select the part icon in the Assets folder. In the Inspector window, click the pulldown menu for Texture Type and change this from Default to Sprite (2D and UI), then click Apply. If this is not done, your lovely icon will not display!
  5. Make Root Part Addressable: Select the root part’s prefab in the Assets folder and in the Inspector window check the box for Addressable.
  6. Make JSON Addressable: Select the part’s JSON in the Assets folder and in the Inspector window check the box for Addressable.
  7. Make the Icon Addressable: Select the root part’s icon in the Assets folder and in the Inspector window check the box for Addressable.
  8. Configure Addressable Properties: In the Addressables Groups expand your mod's Group and find your part.
    1. Group Name \ Addressable Name: Change the information in the Group Name \ Addressable Name from Assets/<part_name>* to be just <part_name>*. So Assets/<part_name>.prefab becomes <part_name>.prefab, and so forth. You can leave the Assets/ part of the path definition alone for each of these, that’s as it should be. The value for the Addressable Name needs to be the same as the file name it’s associated with and must not include any path parts. All of these need to be based on the Part Name established in the Core Part Data module.
    2. Labels: For the JSON set this to parts_data. Leave it blank for the prefab. If parts_data is not an option in the dropdown for Labels, then click Manage Labels, click the + button to add a new label, and set the Label Name to parts_data. Click Save.
  9. Build Mod or Build And Test: Select either Build Mod or Build And Test to have KSP2 Unity Tools prepare and deploy your parts pack mod.
  10. Launch Game and Test!
  11. Rinse and Repeat for Additional Parts

Mentions

This guide is based on the videos: How to create parts for KSP2 and How to make engines for KSP2 (see: Part modding videos (tutorials)), and on other notes and guidance from the KSP2 Modding Society discord.

Also the web pages: KSP2 Part tutorial (almost) from scratch, and Tutorial: My First Part