• Developer Articles


    Damion Rayne

    By Damion Rayne, in Developer Articles,



     
    Announcing Kerbalkon 2012 and Kerbal Space Programs 2nd Anniversary Event!
     
    Come and Join us on November 30th 2012 at 0800/8AM CST (0900/AM EST) (1400/2PM GMT)
     
    What can you expect? 16 hours of awesome plus more!
     
    16 Hours of Dedicated Team KSP/Squad Content
     


     


    [*=center]Announcements!
    [*=center]Contests!
    [*=center]Dev Talks!
    [*=center]Special Previews of upcoming services!
    [*=center]Special Youtuber Guests such as KurtJMac, Scott Manley and The Winter Owl plus others!




    Master of Ceremonies: Team KSP Community Manger - Damion Rayne
    Assitant MOC: Team KSP Community Manager - Capt_Skunky

    Team KSP

    Lead Game Developer:
    Felipe Falanghe (a.k.a HarvesteR) 
    Game & Server Developers:
    Alejandro Mora
    Rob Nelson (a.k.a N3X15)
     
    Game & Tools Developer:
    Mike Geelan

    Technical Artist:
    Chad Jenkins (a.k.a. C7)
     
    3D Artist:
    Daniel Rosas
     
    Content Design:
    Jeff C. (a.k.a. NovaSilisko)
    Jacobo Rosas
    Ean Moody

    Sound & Music Design:
    Edú Castillo

    Programming:
    Mario Maqueo
    Marco Salcedo
     
    Additional Art:
    Juan Carlos Demeneghi
    Iván Vázquez
     
    Community Manager:
    Anthony Keeton (a.k.a Damion Rayne)
    James Kupperian (a.k.a. Skunky)
     
    Executive Producers:
    Ezequiel Ayarza
    Adrián Goya


    Damion Rayne



    Community Spotlight

     
    As a game designer, sometimes it's hard to let go of your game and let it out into the world for people to play it, and tell you what they think of it. Even harder still, is opening your game and allowing someone else to add their own content to it. Well, KSP has been designed from the start for this very thing, we love seeing what you create and what you can make the game do with the tools we give you, while we strive to grow our game even more. Today, I'd like to take some time to spotlight and mention a very prominent figure in the KSP Modding Community, R4mon. Who is R4mon? Let me tell you...
     
    http://forum.kerbalspaceprogram.com/showthread.php/12384-PLUGIN-PART-0-17-Anatid-Robotics-MuMech-MechJeb-Autopilot-v1-9-3
     
    If you follow think above, you'll find yourself in a thread for one of the most popular mods KSP has to offer it's player base, "MechJeb." This mod's been a huge success and proved what a patient mod maker with tools and time could do. MechJeb has been in development for a good while now and continues to grow and adapt to the changes in KSP, and we can't wait to see what he does with it next.
     
    http://forum.kerbalspaceprogram.com/showthread.php/9270-0-17-Multiversal-Mechatronics-Munolith-Research-Division-1-3
     
    The link above is to yet more work, showing r4mon's continued commitment to building mods that play to what we're doing in the main game, and when the "munolith" came out he built a mod designed to hunt them down.
     
    http://forum.kerbalspaceprogram.com/showthread.php/12329-0-17-Multiversal-Mechatronics-Fixed-Camera-1-2
     
    Last but not least, is the fixed camera mod for KSP. Not a lot to discuss here, but a fun little mod to check out nonetheless, we suggest you give it a try.
     
    So, in closing, we want to say thank you to the mod community for showing us your talent, sharing with us your creations and letting us know people are passionate about KSP enough to spend time developing something else for the community to enjoy together.
     
    Damion Rayne
    Community Manager
    HarvesteR
    Hi,

    Continuing on the last article, where I explained how to set up a ScenarioModule to run your own logic on a scene, without requiring a part on your vessel, here's another short guide. This one about writing your own tutorials:


    Tutorials are nothing more than specialized ScenarioModules. To make writing tutorials as simple as possible, we created a TutorialScenario base class, which handles the basic systems for the tutorial, like managing the instructor dialog and the page flow, so you can focus on the content itself.


    So to get started, here is a simple tutorial implementation. I'll explain what each bit does as we go:



    using System.Collections;
    using UnityEngine;

    // Tutorials extend TutorialScenario (which in turn extends ScenarioModule).
    public class TutorialDemo : TutorialScenario
    {

    TutorialPage defaultPage1, defaultPage2, defaultPage3, specialPage1;
    KFSMEvent onSomethingUnplanned, onTutorialRestart;
    KFSMTimedEvent onStayTooLongOnPage1;

    protected override void OnAssetSetup()
    {
    instructorPrefabName = "Instructor_Gene";
    }

    protected override void OnTutorialSetup()
    {
    // start up a default tutorial demo

    defaultPage1 = new TutorialPage("default page 1");
    defaultPage1.windowTitle = "Tutorial Window";
    defaultPage1.OnEnter = (KFSMState st) =>
    {
    instructor.StopRepeatingEmote();
    };
    defaultPage1.OnDrawContent = () =>
    {
    GUILayout.Label("This is a demo tutorial to test out the tutorial scenario features." +
    " Press Next to go to the next page, or wait " +
    (10 - Tutorial.TimeAtCurrentState).ToString("0") + " seconds." , GUILayout.ExpandHeight(true));

    if (GUILayout.Button("Next")) Tutorial.GoToNextPage();
    };
    Tutorial.AddPage(defaultPage1);


    defaultPage2 = new TutorialPage("default page 2");
    defaultPage2.windowTitle = "Tutorial Window (continued)";
    defaultPage2.OnEnter = (KFSMState st) =>
    {
    instructor.PlayEmoteRepeating(instructor.anim_idle_lookAround, 5f);
    };
    defaultPage2.OnDrawContent = () =>
    {
    GUILayout.Label("This second page is only here to test the state progression system." +
    " Tutorial pages can be stepped forward, and also stepped back.", GUILayout.ExpandHeight(true));

    GUILayout.BeginHorizontal();
    if (GUILayout.Button("Back")) Tutorial.GoToLastPage();
    if (GUILayout.Button("Next")) Tutorial.GoToNextPage();
    GUILayout.EndHorizontal();
    };
    Tutorial.AddPage(defaultPage2);


    defaultPage3 = new TutorialPage("default page 3");
    defaultPage3.windowTitle = "Tutorial Window (last one)";
    defaultPage3.OnEnter = (KFSMState st) =>
    {
    instructor.PlayEmoteRepeating(instructor.anim_true_nodA, 5f);
    };
    defaultPage3.OnDrawContent = () =>
    {
    GUILayout.Label("This third page is also only here to test the state progression system." +
    " It's very much like the previous one, but it has a button to restart the tutorial.", GUILayout.ExpandHeight(true));

    GUILayout.BeginHorizontal();
    if (GUILayout.Button("Back")) Tutorial.GoToLastPage();
    if (GUILayout.Button("Restart")) Tutorial.RunEvent(onTutorialRestart);
    GUILayout.EndHorizontal();
    };
    Tutorial.AddPage(defaultPage3);


    specialPage1 = new TutorialPage("special page 1");
    specialPage1.OnEnter = (KFSMState lastSt) =>
    {
    specialPage1.windowTitle = "Tutorial Window (from " + lastSt.name + ")";
    specialPage1.onAdvanceConditionMet.GoToStateOnEvent = lastSt;

    instructor.PlayEmote(instructor.anim_true_thumbsUp);
    };
    specialPage1.OnDrawContent = () =>
    {
    GUILayout.Label("This Page shows that it's possible to use external events to send the tutorial to" +
    " any arbitrary state, even ones not in the default sequence. Use this to handle cases where the" +
    " player strays off the plan.\n\nNote that this page is added with AddState instead of AddPage," +
    " because we don't want this page to be part of the normal tutorial sequence.", GUILayout.ExpandHeight(true));

    if (GUILayout.Button("Yep"))
    {
    Tutorial.RunEvent(specialPage1.onAdvanceConditionMet);
    }
    };
    specialPage1.OnLeave = (KFSMState st) =>
    {
    instructor.PlayEmote(instructor.anim_idle_sigh);
    };
    Tutorial.AddState(specialPage1);


    onTutorialRestart = new KFSMEvent("Tutorial Restarted");
    onTutorialRestart.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
    onTutorialRestart.GoToStateOnEvent = defaultPage1;
    Tutorial.AddEvent(onTutorialRestart, defaultPage3);


    onSomethingUnplanned = new KFSMEvent("Something Unplanned");
    onSomethingUnplanned.updateMode = KFSMUpdateMode.MANUAL_TRIGGER;
    onSomethingUnplanned.GoToStateOnEvent = specialPage1;
    Tutorial.AddEventExcluding(onSomethingUnplanned, specialPage1);


    onStayTooLongOnPage1 = new KFSMTimedEvent("Too Long at Page 1", 10.0);
    onStayTooLongOnPage1.GoToStateOnEvent = specialPage1;
    Tutorial.AddEvent(onStayTooLongOnPage1, defaultPage1);

    Tutorial.StartTutorial(defaultPage1);
    }

    // this method would be called by some external component...
    public void SomethingUnplanned()
    {
    if (Tutorial.Started)
    {
    Tutorial.RunEvent(onSomethingUnplanned);
    }
    }

    }




    Yes, quite a bit of code I know, but we'll take in parts.

    The First thing you see on the class there are declarations of TutorialPage objects and some KFSMEvents. That is the basis of the tutorial system. The tutorial flow is managed by a state machine, which is based off the same one that the Kerbal EVA controller uses. It is based around the concept of States and Events. States hold the code that gets run when that state is active, and Events are used to move from one state to another.

    The TutorialScenario has a built-in tutorial FSM called Tutorial, as you can see above. In the OnTutorialSetup method, you create the tutorial pages and the events that will change them, add it all into the Tutorial solver, and start it.

    Before we get more in-depth about that, let's look at that OnAssetsSetup method. That method is called on Start, before anything else can run, to allow you to define your assets to use in the tutorial. The demo above only sets the intructor to be Gene instead of Wernher (who is the default), but as you will see on the other examples later, that method is also used to load or grab references to other assets that might be necessary.


    Back to the tutorial setup then, let's look at a page definition again:



    defaultPage2 = new TutorialPage("default page 2");
    defaultPage2.windowTitle = "Tutorial Window (continued)";
    defaultPage2.OnEnter = (KFSMState st) =>
    {
    instructor.PlayEmoteRepeating(instructor.anim_idle_lookAround, 5f);
    };
    defaultPage2.OnDrawContent = () =>
    {
    GUILayout.Label("This second page is only here to test the state progression system." +
    " Tutorial pages can be stepped forward, and also stepped back.", GUILayout.ExpandHeight(true));

    GUILayout.BeginHorizontal();
    if (GUILayout.Button("Back")) Tutorial.GoToLastPage();
    if (GUILayout.Button("Next")) Tutorial.GoToNextPage();
    GUILayout.EndHorizontal();
    };
    Tutorial.AddPage(defaultPage2);


    TutorialPages are states in the tutorial state machine. They have a number of callback that get called as the tutorial progresses, in which you can add your own code. This demo uses a coding style known as lambda expressions to assign logic to each callback , without having to write methods somewhere else in the code. This is just to keep it all in one place, and you can do it the conventional way if you prefer.

    So, here's what each callback means. Note that you don't really need to assign a method to every one of them. They all default to an empty method, so it's safe to omit the ones you don't need.

    TutorialPage.OnEnter(KFSMState st) gets called once when the page becomes the active one. The 'st' parameter is a reference to the last state before this one.

    TutorialPage.OnUpdate() gets called repeatedly (from Update), to let you run your update logic for the state.

    TutorialPage.OnFixedUpdate() gets called repeatedly (from FixedUpdate), to let you run your fixed update logic for the state.

    TutorialPage.OnLateUpdate() gets called repeatedly (from LateUpdate), to let you run your late update logic for the state.

    TutorialPage.OnDrawContent() gets called repeatedly (from OnGUI) to let you draw your GUI content using Unity's GUI classes.

    TutorialPage.OnLeave(KFSMState st) gets called once when the tutorial is about to move to a new page. The 'st' parameter is a reference to that next state.

    TutorialPage.GoToNextPage() call this to make the tutorial go to the next state. Pages are sequenced by the order in which they get added.

    TutorialPage.GoToPrevPage() same as above, only goes back to the previous page.

    TutorialPage.SetAdvanceCondition(KFSMEventCondition c) Use this to set a condition which will be evaluated repeatedly to advance to the next step when the condition is met. This is just a convenience method to reduce repeated code. It's the same as checking for the same condition on one of the state update events and manually calling GoToNextPage.


    After your page is all set up, you add it to the tutorial sequence with Tutorial.AddPage(yourPage).

    Events can be used along with tutorial pages, to manage situations where the player strays from the plan. Events come in two forms: KFSMEvents and KFSMTimedEvents. KFSMEvents are similar to states (and pages) in some ways. They also have callbacks that get called at specific times. They also have a GoToStateOnEvent value, which holds a reference to the state you want to transition to after the event is triggered. Events are defined independently so when you add them, you can assign them to any combination of states. If you've ever seen an FSM diagram, the analogy becomes simple. States are the nodes, and Events are the arrows that connect each node.


    On the demo above, we have a TimedEvent assigned to run on page 1 of the tutorial. It's set to go off after ten seconds, and take you to a special page. You'll notice that this special page isn't a TutorialPage object, but a KFSMState. That's fine, since TutorialPage is just an extension of KFSMState. Adding a state that isn't a page to the tutorial is perfectly possible. Also notice that the special page is added by calling Tutorial.AddState instead of AddPage. This lets the tutorial know that this page isn't part of the standard sequence, so it doesn't get in the way of the normal flow when calling GoToNextPage, for instance.


    That's about it for how tutorials work. However, the demo above doesn't really show the more hands-on practices of writing a proper tutorial, so I'm also attaching here the source code for the Orbiting 101 tutorial, in full. That should hopefully be a good example of how a tutorial can be written using this system (I recommend turning word wrap on to read the Orbit101 code).

    Happy coding!

    Cheers

    PS: The attachment manager thingy decided to not let me upload a .cs file directly, so I changed the extension to .txt - Just change it back to .cs to open it as a normal code file.
    HarvesteR
    It ocurred to me that there is little to no documentation at this point about the new ScenarioModules and how to add them to your game. With that in mind, I've written this brief guide as to how they are used. I'm assuming you already have some experience writing PartModules, in which case it should be relatively straightforward to learn how ScenarioModules operate. If not, I strongly suggest reading through the available PartModule coding tutorials and (admittedly very incomplete) documentation first.

    Let's get started then:

    Scenario Modules, just like PartModules, are compiled into dlls that go in the Plugins folder. In fact, nothing stops you from having ScenarioModules sharing dlls with PartModules. The dlls in Plugins simply add their classes to the game assembly.

    Once added, a ScenarioModule is loaded into the game through SFS files. In very much the same way you set up a PartModule in a part.cfg, you set up a ScenarioModule in an .sfs file:



    GAME
    {
    version = 0.17.0
    Title = Orbiting 101
    Description = This training scenario covers the basics of flying a blablabla....
    // mode 0: Sandbox - mode 1: Career (not available yet), mode 2: Scenario, mode 3: Non-Resumable Scenario
    Mode = 3
    // scene to load when starting this save.
    scene = 7
    PARAMETERS
    {
    // flight parameter stuff
    }
    FLIGHTSTATE
    {
    // flight state data (in 0.16 this was your entire sfs file)
    }
    SCENARIO
    {
    // the name of the ScenarioModule class to spawn
    name = TutorialOrbit101
    // the scene in which the module gets spawned (7 = flight)
    scene = 7
    }
    }


    The only limitation at the moment is that to add a scenario module to your ongoing sandbox game, you'll need to manually add the module config to your persistent.sfs. Once added, it gets loaded into the persistence data structure and will remain in your sfs file even as it gets resaved and rewritten.

    ScenarioModules have one main difference from PartModules though. Because they are made to run on any scene, you must specify a target scene in which your module will run. Currently, modules can only run on one scene at a time. When a scene starts, the scenario module runner attaches all ScenarioModules that target that scene as a MonoBehaviour on an empty game object in the scene. You can use all MonoBehaviour events (except Awake), and code it in very much the same way you code part modules... Of course, there is no reference to vessel or part, since the module isn't attached to one.


    Hope this helps.

    Cheers
    C7Studios
    Welcome to the modder's corner! Today, I'll be going over the topic of basic modding. We'll be covering where to find the files you can modify, and how they work. Later, I'll be getting into more advanced topics, such as setting up landing gear and editing the internal spaces.

    Feel free to ask for clarification in the comments if something isn't clear, or if you have any questions about how things work.
     
    Part Config Files
    The main part config files are stored in the KSP\Parts\ Folder. Each directory in this folder is a specific part in the game. In the picture below, you can see a standard part folder. In this case, the advanced canard.
     

     
    File types:
    model.mu - files contain the 3d model, and other Unity information. Such as part colliders, material settings and shaders. This file is created by KSP part tools on export.
     
    model000.mbm - files contain textures for parts. The number increases for each additional texture file the part has. This is also created by KSP part tools.
     
    part.cfg - This contains all the settings and information about a part, and is required to be in the folder for a part.
     
    The easy way to get started modding is just to open up a part.cfg file and take a look inside. Most of the information in the part.cfg is easily readable and can be changed with a standard text editor.
     
    Here is an example part.cfg file that you can take a look at. Lines that start with
    // are comments and are ignored on loading. I've commented the file in blue to say what each line is. This is changed a bit to show some concepts from other part.cfg files.
     
    // --- general parameters ---name = AdvancedCanard This is the identifier for the part, it should always be unique, remember to change it if you're making a part based off another one.
    module = ControlSurface This is the code that the part will use as a base, you can look at the other part.cfg files to see some of the available part types. If you want a blank slate to add modules to, set this to Part.
    author = C. Jenkins Your name!
     

    // --- asset parameters ---
    mesh = model.mu When using the new part tools, set this to model.mu You'll find that older mods and files may still use .dae mesh files. In general, if you're just changing a part's behavior you can leave this be.
    scale = 0.1 This changes the scale of the attachment nodes, you can use it to correct for the units that your model uses.
    rescaleFactor = 1.25 This determines the factor at which the part is rescaled, you can change this to adjust if your part is too big or small in the game. It will automatically scale the 3d models and colliders for you. If this parameter is not set, the game will scale the parts to the default of 1.25. Just keep in mind the default for parts is actually a 1.25 not 1!
     
     

    // --- editor parameters -- These lines determine the part information as seen in the VAB of the game.
    cost = 500 Cost of the part in campaign mode
    category = 1 Part category in the editor
    subcategory = 0 Currently not used
    title = Advanced Canard The in game name of the part
    manufacturer = C7 Aerospace Division Your manufacturer!
    description = Our engineers thought this design looked "high tech" and therefore must be clear improvement on earlier models.
    // attachment rules: stack, srfAttach, allowStack, allowSrfAttach, allowCollision
    attachRules = 0,1,0,1,0 Attachment rules control how the part is attached in ship builder. A 0 means that this attachment method is not allowed, and a 1 means that it is.
    stack - does this part use attachment nodes?
    srfAttach - does this use surface attachments?
    allowStack - allow this to be stacked upon
    allowSrfAttachment - allow things to attach to the surface of this part.
    allowCollision - Can this be placed while colliding with another part in the ship editor?
     
    // --- node definitions ---
    // definition format is Position X, Position Y, Position Z, Up X, Up Y, Up Z
    node_attach = 0.0, 0.0, 0.0, 1.0, 0.0, 0.0
    node_stack_top = 0.0, 7.72552, 0.0, 0.0, 1.0, 0.0
    node_stack_bottom = 0.0, -7.3, 0.0, 0.0, 1.0, 0.0
    node_attach - this defines the position and rotation (in local units) that the part will attach to another. Only relevant if you have srfAttachment enabled
    node_stack - Only relevant if you're using stacking attachment defines a stack node. They can be followed by _top _bottom, _bottom1, _bottom2 etc.
     
     

    // --- standard part parameters ---
    mass = 0.04 The weight of the part
    dragModelType = override The drag model, usually just set this to default or override for dynamic parts like this winglet
    maximum_drag = 0.02 How much drag this part can have at max
    minimum_drag = 0.02 Not actually used!
    angularDrag = 3 How much rotational drag this part experiences. (Will stop things from spinning due to drag while in atmosphere)
    crashTolerance = 12 The amount of impact this can take before exploding
    maxTemp = 3400 Max temperature before overheating
    explosionPotential = 0.1 How big of a boom does this make?
    fuelCrossFeed = True Will this allow fuel or resources to flow through it? True / False
     

    // --- winglet parameters --- Many parts have values that are specific to them. They're included typically at the end of the part.cfg file.
    // dragCoeff will override the maximum_drag value
    dragCoeff = 0.5
    deflectionLiftCoeff = 0.7
    ctrlSurfaceRange = 20
    ctrlSurfaceArea = 0.9

    Adding Part modules

    Moving forward more and more of the base parts are going to be modules. In the case of a part module. You can start by basing your part off a blank slate. Instead of choosing module = FuelTank, or module = ControlSurface. You can set a part to module = Part. This includes only what is necessary code wise to make the part exist in game. After that you can extend this blank state by adding part modules to the cfg file. A good example of this is the SmallGearBay, which is just a landing gear module put on the blank "Part" slate.
     
    If you wanted to add the landing gear module to another part, its quite simple to do so. You just need to add a module definition to the part. Keep in mind, that a lot of complicated modules need things in their model.mu file to work. In the case of a landing gear, they need to have wheels, suspension, a Unity wheel collider, bounds and things attached to them! However simpler code modules like fuel tanks, could be added with no extra requirements in the actual model files.
     
    At the bottom of your part.cfg file, its as simple as adding the line
     
    MODULE
    {
    name = ModuleLandingGear
    }
     
    Each module consists at bare minimum of this definition. Module, follow by open / closed brackets, and the name of the module you want to attach.
     
    In this case, its using all the default parameters for the landing gear. So there's nothing else to add. In another post, I'll go over all the things you can add to the module definition of the landing gear when I cover that topic in detail.
     
    Internal Spaces
    Another good example of this is Internal spaces.
     
    You'll notice they follow a very similar format! Just add this to the bottom of your part.cfg to make it crewable. Keep in mind, that without an airlock your poor kerbals won't have any way to get in or out! I'll go into airlocks, and making crewable spaces more in another post.
     
    CrewCapacity = 3 // This will determine the max crew capacity of the part
     

    INTERNAL
    {
    name = PodCockpit
    }
     

    Again we just start the block off with INTERNAL, open and closed brackets, and another, name = InternalSpaceName.
     
    This name will typically correspond to a folder in the internal spaces directory. It works very much like the parts do. Where the main folder is called Internals\Spaces\ and the sub folders are for each internal space. You can open the internal.cfg files to see the names of each internal space.
     

     
    In here you'll see a familiar structure. The main file is the internal.cfg. Along with the model.mu and model.mbm texture files.
     
    Let's take a peek at an internal file!
     
    Internal.cfg
     
    To keep this post from being incredibly long I've left out the rest of the props, but you should get the general idea. Feel free to open up your local copy of the file to see how the rest works if you like.
     
    These files follow the structure of all modules, they're using the new configNode system. If you want more information on how these work, Mu has posted an excellent and in depth article on the subject.
     
    I'll annotate everything in blue as I've done with the previous information.
     
    INTERNAL This begins the definition of the internal space, just like any module
    {
    name = mk1CockpitInternal This is the name of the module we're defining, to keep it clear and standardized, make sure this name matches the name of your internal space directory.
     

    MODULE Here were adding a seat module for each pilot seat in the internal space, again its following the same pattern as before.
    {
    name = InternalSeat The name of the module we're adding, an internal seat in this case
    seatTransformName = CenterSeat The name of the game object where the kerbal will be spawned in IVA. This is added to the model.mu in Unity and exported.
    portraitCameraName = CockpitCam If you're overridding the camera for this seat, you can define it here. Its done by name of the Unity Game object.
    allowCrewHelmet = false is the pilot allowed to wear his helmet in this space? In the case of the aircraft cockpits, they don't wear them due to the large size. In a command pod, they would wear the helmets.
    }
    MODULE Adding another module, in this case, an internal camera for the IVA, hot spot selection. This allows the camera to focus in on an object when you double click, such as the windows!
    {
    name = InternalCameraSwitch Module name again
    colliderTransformName = focusCanopy The name of a gameobject you used in Unity to define a clickable area, it should have a collider attached to it.
    cameraTransformName = CanopyEyeTransform This is the name of the unity game object the camera will move to.
    }
    PROP Here we're adding a prop module to the internal space.
    {
    name = ButtonSquare The name of the prop we're adding (They're defined in the Internals/Props/ Folder, like the internal spaces are defined.
    position = -0.1184633, 0.2851815, -0.9793196 X, Y, Z Position Information (In Local Space co-ordinates, for your internal space model)
    rotation = 0.5576651, 0, 0, 0.8300661 The rotation values in local space, of the prop.
    scale = 1, 1, 1 X, Y, Z Scales of the object
    }
    }
     
    Internal Props

    Internal Props are defined just like parts or internal spaces. Their files are in the Internals\Props\NameOfProp\ folders. In there, you'll find the standard model.mu files, model.mbm texture files, and a new file. The prop.cfg.
     
    The prop.cfg contains all the information for a specific prop. These props are then added the internal.cfg files of an internal space. Where you provide the position and rotation information for them. A prop only needs to be defined, once, and can be added over and over again to an internal space.
     
    Here is an example prop.cfg file for the 3 handed altimeter gauge.
    Like all the prop files, it mostly consists of some information that the prop needs to work. In this case, it needs to know the name of each hand's game object, so it can find it and rotate it.
     
    PROP Start of our prop definition
    {
    name = AltimeterThreeHands The name of our prop, should match the prop's folder name, though its technically not necessary. You can have multiple props in the same directory, but it can get a little complicated.
     

    MODULE
    {
    name = InternalAltimeterThreeHands The name of the module we're adding
    hand100Name = LongArm The name of the long hand's game object in Unity.
    hand1000Name = MediumArm
    hand10000Name = ShortArm
    }
    }
     

    proxy = 0, 0, 0, 0.06, 0.01, 0.06, 1.0, 0.5, 0 Prop tools uses this to create a box when you load the part in prop tools. It will allow you to snap the object down and place it easier in the Unity editor. It defines the x, y, z position, size and rgb color information for the prop's proxy.
     
    That's it for today. I'll go over more topics in detail as time permits. But this should give you a good, general idea of how the config files relate to eachother, and the formats they use. Feel free to post comments below, so I can improve future posts, and answer any questions.
     
    Thanks!
     
    -C7
     

    Community Added Suggestions and Information
     
    By Tiberion,
    A note on something I have found using the rescaleFactor confg setting;
     
    It also scales up the position of your attachment nodes, as well as the origins and vectors of things like RCS or engine thrust exhaust FX.
     
    This means when making a new part or editing an old one, you work on those parameters as if the model were its natural size (1.0, not the default scale of 1.25) You might even want to set the factor to 1.0 when setting it up for the first time, then remove it or set it to your target scaleFactor.
     
    Quick example:
     
    You model a 2meter tall fuel tank, and the top and bottom nodes would be 0,1,0 and 0,-1,0 (+/- 1 meter from the parts origin, assuming its in the very center of the model/collider)
     
    By default that tank is going to be scaled up to 2.5 meters tall (2 x 1.25) but you would still config your nodes using the original meshes you made; in game the nodes will appear at +/- 1.25meters (1 meter x 1.25 rescaleFactor = 1.25meters) without any work on your part.
     

    Just something to keep in mind.
    HarvesteR
    People have asked for it, so I thought it would be a good idea to promote this post I made a while back into a forum article. Hooray for VB!




    When I was little, I used to build model balsa-wood airplanes, and I learned some useful rules of thumb that might be worth sharing:

    One, if it looks like a plane, it will probably fly like a plane. Try a very conventional design before you go for the successor to the SR-71.


    The KRJ-100. Looks very much like a plane. It will glide without input.

    Two, the center of mass should be at the first third of the wings. Mentally divide your wing into three sections. The plane should be balanced at the first division threshold. (landing gear can be just aft of that, to provide a nice fulcrum)


    The KRJ-400 JetLiner, it\'s as heavy as it looks like.


    Three, vertical stabilizers should actually be pushing down, not up. Use the rotation feature in the SPH to pitch your elevators down a notch or two before placing. The wings alone will make the plane pitch down, while the stabilizers keep the nose up. Planes are stable when those forces even out.


    The Annihilator Mk1, the V tail acts as both rudder and elevator, and they\'re pitched down 10 degrees.


    Four, canards are like pushing on a rope. See rule 1.


    The Ravenspear Mk1 is much trickier to fly than the Annihilator. Pitch too aggressively, and it will tumble out of control.


    That\'s about it for now, hope this helps.

    Cheers