Prop Config - MOARdV/AvionicsSystems GitHub Wiki

Prop Config is a tool designed to automate prop generation. It allows props to be collected into arbitrary groups and output into separate folders based on those groups. Within each group, Prop Config allows the definition of one or more Styles. A Style is a collection of MODEL elements, MODULE elements, and MASComponent elements that defines common traits found in props. Each element in a Style may be overridden in the prop config, and additional fields may be added by a prop to further customize it.

Prop Config uses XML files for input. One or more XML files may be provided on the command line, ie. PropConfig.exe myprops.xml otherprops.xml.

One caveat about Prop Config: it is a fairly dumb tool. You can tell it to create invalid MASComponent nodes, and you can reference textures and models that don't exist. Making it smart enough to ensure the models and textures exist in the KSP installation, and that only valid MASComponent nodes are created would make it run slower, and it would mean that it must be updated at the same time that new features are added.

Starting with Prop Config v1.1.2, config files are written only if they did not already exist, or if the XML file is newer than an existing config file. To force Prop Config to regenerate all config files, regardless of their date stamp, include --force as the first command-line parameter (eg, propConfig --force myprops.xml.

NOTE: Capitalization matters. An element named model is not the same as an element named MODEL.

XML Layout

An example of the PropConfig XML file can be found in the repo under prop.xml.

Root Node

The root node must be named PropConfig:

<PropConfig>
  ...
</PropConfig>

Prop Groups

A prop group is a collection of props that generally share common characteristics, such as ASET modular toggle switches. Each prop group should include a folder attribute. This folder tells PropConfig where to write the config files for that prop group. If the folder attribute is missing, PropConfig will write the group's configs in the current directory. PropConfig creates these folders relative to the current working directory if they are not a full path. A prop group may have any name for its element - PropConfig will display that name as part of its output, but the name has no effect on prop generation.

The folder attribute may consist of a nested folder, eg "Switch_Toggle_Modular/aircraft". UNTESTED

<ToggleSwitch folder="Switch_Toggle_Modular">
  ...
</ToggleSwitch>

Each prop group contains two categories of child elements: styles and props.

A style consists of a set of configuration values that are shared by multiple props. The style provides a template that is used to build a prop's config file.

A prop defines an actual prop that will be created by PropConfig. It consists of a name, a style, and overrides for nodes in the style. Any field in a style may be overridden, and a prop may add additional fields to any prop. In addition, it may add whole new MASComponent or MODEL nodes to the config file.

Style

A Style defines the common values used in a particular style of prop. It consists of one or more MODEL elements and any number of other elements that correspond to MASComponent nodes. The style defines the default values for all of these common nodes. A Prop may override these defaults. Each style must include a name attribute so that PropConfig can identify it later. The name may be any valid string, and it should not be duplicated within a prop group element. Duplicate style names may be used in different prop groups, however.

<style name="MOARdV Power Switch">
  <MODEL>
    ...
  </MODEL>
  ...
</style>

Prop

A Prop defines a single prop. It consists of a name element, a style element, zero or more MODEL override elements, and zero or more MASComponent override elements.

<prop>
  <name>MAS.toggle_ARRT_Power</name>
  <style>MOARdV Power Switch</style>
  <startupScript>SwitchInitializer()</startupScript>
  <COLLIDER_EVENT id="0">
    <onClick>ARRT_TogglePower()</onClick>
  </COLLIDER_EVENT>
  <ROTATION>
    <variable>fc.GetPersistentAsNumber("MAS_ARRT_On")</variable>
  </ROTATION>
  <TEXT_LABEL id="0">
    <text>ON</text>
  </TEXT_LABEL>
</prop>

The name element may contain any name that can be used for both a file name and a KSP prop name. PropConfig will automatically replace any empty space or period . characters in the name with an underscore _. In the example above, the prop is named "MAS.toggle_ARRT_Power". The config file is named "MAS_toggle_ARRT_Power.cfg".

The style element names the Style that is used as a template for this prop. If an invalid style is selected, PropConfig will skip the part.

The startupScript element is optional, and it may be omitted. When present, this element defines the startupScript that will be executed by the MASComponent when it loads and initializes upon entering the Flight scene. Refer to MASComponent for more information on the startup script.

Within a prop element, you may add new MODEL, MODULE, or MASComponents by specifying all of the fields that need to be in that config node. Make sure you use a unique id for the new node. You may also delete nodes from the Style by adding the attribute delete="true":

<prop>
  ... // name, style, overrides omitted
  <TEXT_LABEL id="1" delete="true" />
</prop>

In the above example, the TEXT_LABEL with id="1" in the prop's style is deleted. Using this approach may reduce the number of unique styles that need to be created.

MODEL

Both Styles and Props may include MODEL elements. A MODEL element is converted into a MODEL node in the config file. Each MODEL element should include one model element, an optional comment element, and zero or more texture elements. When more than one MODEL element is required in a prop (such as the ASET modular props), each MODEL element must be identified by an id attribute, which is an integer number. If the id attribute is omitted, it defaults to 0.

<MODEL id="1">
  <comment>Basic toggle</comment>
  <model>ASET/ASET_Props/Control/Switch_Toggle_Modular/models/TgglLever_Type_5</model>
  <texture>Switch_TUMBLEDiffuse,ASET/ASET_Props/Control/Switch_Tumble/Switch_TUMBLEDiffuse</texture>
  <texture>Tggl_Cap_Diffuse,ASET/ASET_Props/Control/Switch_Toggle_Modular/models/Tggl_Cap_White</texture>
</MODEL>

In this case, the MODEL has an id of 1, so if a Prop needs to edit this MODEL for some reason, it will also need to use <MODEL id="1">.

The above MODEL element results in the following output in the config file:

// Basic toggle
MODEL
{
  model = ASET/ASET_Props/Control/Switch_Toggle_Modular/models/TgglLever_Type_5
  texture = Switch_TUMBLEDiffuse,ASET/ASET_Props/Control/Switch_Tumble/Switch_TUMBLEDiffuse
  texture = Tggl_Cap_Diffuse,ASET/ASET_Props/Control/Switch_Toggle_Modular/models/Tggl_Cap_White
}

Although they are not included in this example, the MODEL options for scale and rotation may also be included in the XML script.

MODULE

Both Styles and Props may include MODULE elements. A MODULE element is converted into a MODULE node in the config file. This element is useful for adding minor additional functionality to a given prop. It will support a simple prop module; that is, a module that does not contain nested nodes. The original impetus for this element was to support the Flight Director/Attitude Indicator prop, which uses a MASNavBall module in addition to a MASComponent.

Like the MODEL element, a MODULE element contains multiple child elements. The MODULE element also supports the comment child element like the MODEL. Each child element is converted into a ConfigNode name/value pair. For example,

<MODULE>
  <name>MASNavBall</name>
  <navBallName>NavSphereRotGO</navBallName>
  <range>-0.5, 0.5</range>
  <maxAngleChange>180</maxAngleChange>
  <variable>fdaiOffFlag(1)</variable>
</MODULE>

results in the ConfigNode

MODULE
{
  name = MASNavBall
  navBallName = NavSphereRotGO
  range = -0.5, 0.5
  maxAngleChange = 180
  variable = fdaiOffFlag(1)
}

MASComponent

Any element in a Style or Prop that is named neither MODEL nor MODULE is treated as a MASComponent node. The name of the node in the config file is exactly the same as the name of the element. For instance, if the element is called <ROTATION>, then the config file will include a node named ROTATION. If more than one node of the same type is used in the prop, each element should be given a unique id in the same way described for MODEL. If an element does not have an id, it defaults to 0.

Like the MODEL element, a MASComponent element contains multiple child elements. The MASComponent element also supports the comment child element like the MODEL. Each child element is converted into a ConfigNode name/value pair. For example,

<ROTATION>
  <variable>fc.GetPersistentAsNumber("MAS_IMP_On")</variable>
</ROTATION>

will result in

MODULE
{
  name = MASComponent

  // Other nodes omitted
  ROTATION
  {
    variable = fc.GetPersistentAsNumber("MAS_IMP_On")
  }
}

in the prop config file.

XML Limitations

Because the prop configuration script is an XML file, certain characters are illegal. These characters are part of MAS variable text processing, so some workarounds must be applied.

  • <= and => may not be used for string formatting in a <text> (or any other) element. Instead, use the standard C# { and }. Prop Config will convert them for you.
  • & may not be used, so $#$ should be used in prop configuration XML files to separate string formatting information from the variable list (for instance, {0:0.00} $#$ fc.Apoapsis() * 0.001).
  • < may not be used for comparisons such as fc.Periapsis() < 0. Use the substitution &lt;. > usually works without a problem, but it may be good practice to use &gt; instead.

These restrictions will primarily affect <text> and <variable>. For instance, if the text field is supposed to be:

<=0:METHHH[@x8]mm[@x16]ss=> $&$ fc.OrbitPeriod()

you may use

{0:METHHH[@x8]mm[@x16]ss} $#$ fc.OrbitPeriod()

Future updates will hopefully provide easier substitution options.

Using Prop Config

Once you create the XML file to create props, run Prop Config from the command line:

PropConfig.exe myprops.xml
  • Prop Config reads the XML file. If there are any XML errors, such as mismatched open/close elements, Prop Config will print the error and skip processing that XML file.
  • Prop Config will process each prop group.

For each prop group,

  • Prop Config reads all of the style elements. Any styles with duplicated names are reported, and only the first style encountered with that name is used.

Within each style,

  • All elements with the name MODEL are processed as MODEL nodes. All other elements are processed as MASComponent nodes.
  • If more than one MODEL element is found in the style, and none have an id attribute, or if multiple MODEL elements are found with the same id attribute, Prop Config will report the duplicates. Only the first MODEL with a duplicated id will be used by the style.
  • Likewise, if more than one MASComponent element is found with matching ids, Prop Config will print a notice and keep only the first one.

Once the styles are processed, Prop Config will process all of the prop elements.

  • If the name contains any whitespace, Prop Config replaces those characters with _ underscore. Prop Config does not test for duplicate prop names.
  • Prop Config searches for the style named in the style element. If a style with that name is not found, Prop Config reports the error and it skips the prop.
  • Prop Config merges the style and the prop elements.

The merging process is as follows:

  • For every MODEL in the style, if the prop does not also have an entry for a MODEL with the same id, then the style's MODEL is used. If the prop has a MODEL with the same id, then Prop Config will copy each field in the MODEL from the style, unless the field exists in the prop as well, in which case the prop`s field is used. The same process is applied to MASComponent elements.

Since this is pretty confusing and important, and I did not explain it well, I'll provide an example:

<PropConfig>
  <SomeProps folder="LameProps">
    <style name="Example Style">
      <MODEL id="0">
        <comment>Unchanged Model</comment>
        <model>Props/Part1</model>
      </MODEL>
      <MODEL id="1">
        <comment>Edit Model</comment>
        <model>Props/Part2</model>
      </MODEL>
      <MODEL id="2">
        <comment>Add To Model</comment>
        <model>Props/Part3</model>
      </MODEL>
      <MODEL id="3">
        <comment>Multiple texture model</comment>
        <model>Props/Part3</model>
        <texture>diffuse,Props/otherDiffuse</texture>
        <texture>emissive,Props/otherEmissive</texture>
      </MODEL>
    </style>
    <prop>
      <name>UselessProp</name>
      <style>Example Style</style>
      <MODEL id="1">
        <model>Props/Part2a</model>
      </MODEL>
      <MODEL id="2">
        <texture>diffuse,Props/differentDiffuse</texture>
      </MODEL>
      <MODEL id="3">
        <comment>Oops - can't edit multiple textures</comment>
        <texture>diffuse,Props/differentDiffuse</texture>
      </MODEL>
    </prop>
  </SomeProps>
</PropConfig>

The above XML will create a prop config file LameProps/UselessProp.cfg. The file will look like

PROP
{
	name = UselessProp

	// Unchanged Model
	MODEL
	{
		model = Props/Part1
	}

	// Edit Model
	MODEL
	{
		model = Props/Part2a
	}

	// Add To Model
	MODEL
	{
		model = Props/Part3
		texture = diffuse,Props/differentDiffuse
	}

	// Oops - can't edit multiple textures
	MODEL
	{
		model = Props/Part3
		texture = diffuse,Props/differentDiffuse
		texture = diffuse,Props/differentDiffuse
	}

	MODULE
	{
		name = MASComponent

	}
}

It's not an interesting prop, since there are no components under MASComponent. But it illustrates the merging system.

One thing to watch out for, especially for MODEL texture fields: there is no way to distinguish between duplicated fields in a style. If a style has a MODEL with multiple texture fields, such as the Part3 MODEL node above, and a prop edits the texture field, all of the style's texture fields are changed. If you need to have MODEL nodes with multiple, different textures, you will have to put each one in its own, separate style.

⚠️ **GitHub.com Fallback** ⚠️