Creating new mod template

Creating a mod template from scratch


Example: Simple Engine mod template

Mods Studio 2 version: 2019.04 or newer

Written on: July 30th, 2019


To create a basic engine mod, you'll first need to create an engine definition file. To get the idea how an engine mod looks, we'll look at engine definitions for the Volvo FH16 (2012). If you have extracted the game def files, you can open def\vehicle\truck\volvo.fh16_2012\engine to see examples of such files. As we're creating a simple engine mod template, we'll ignore the torque curve data that is introduced on newer engine definitions (see NextGen Scania).

Here is an example of the engine definition from the base game, in this case the  d16g750.sii file:

SiiNunit
{
accessory_engine_data : d16g750.volvo.fh16_2012.engine
{
	name: "D16G750 Euro 5 / EEV"
	price: 25560
	unlock: 16
	info[]: "750 @@hp@@ (551@@kw@@)"
	info[]: "3@@dg@@550 @@nm@@"
	info[]: "1@@dg@@050-1@@dg@@400 @@rpm@@"
	icon: "engine_01"
	torque: 3550
	rpm_limit: 2100
	volume: 16.1
	no_adblue_power_limit: 0.5

	overrides[]: "/def/vehicle/truck/volvo.fh16_2012/badge/badge_750.sii"
	overrides[]: "/def/vehicle/truck/volvo.fh16_2012/c_equip/front_grid_01_cab.sii"
	overrides[]: "/def/vehicle/truck/volvo.fh16_2012/s_equip/front_grid_01.sii"
	overrides[]: "/def/vehicle/truck/volvo.fh16_2012/sound/interior_16.sii"
	overrides[]: "/def/vehicle/truck/volvo.fh16_2012/sound/exterior_16.sii"
}
}

As you can see, there's a lot of data there. In fact, all the data we need. We'll re-use this file later on as a template for our new engine mod files.

Let's add all this now into Mods Studio 2. Open your MS2 folder, and go to Data\ModProjects\ETS2\Templates. In here, create a folder for your new mod template. I'll just call it "SimpleEngine". Inside of this folder, create an empty file called "template.xml". Every mod template needs this file, as MS2 gets all of the information about the mod template from it.

Now, copy the example d16g750.sii file into our SimpleEngine folder". Rename the file to "SimpleEngine.sii". (Note: You can rename the file to whatever you like, as long as you later on use that name.) This is now how your new mod template folder should look:

We want to be able to change all the relevant values in our engine definition file using Mods Studio 2. To achieve this we need to edit our SimpleEngine.sii file and designate variables that MS2 will be able to change. To edit the *.sii file, you can use any text editor. (Eg: Notepad, Notepad++, SublimeText, VS Code... anything really.) Here's how the file should look after you edit it with explanation coming up right after:

SiiNunit
{
accessory_engine_data : {{InternalName}}.{{Truck}}.engine
{
	name: 					"{{EngineName}}"
	price: 					{{EnginePrice}}
	unlock: 				{{EngineUnlock}}
	icon: 					"{{InternalName}}"
	torque: 				{{EngineTorque}}
	rpm_limit: 				{{EngineRpmLimit}}
	volume: 				{{EngineVolume}}
	no_adblue_power_limit: 	{{EngineAdbluePowerLimit}}
{{EngineInfo}}
{{EngineOverrides}}
}
}

First thing to note is - the position of data in a *.sii definition file is not important. Hence info[] is now moved below no_adblue_power_limit.

As you can see, we replaced all important data with variables. When you want MS2 to replace some text in a file, file path or anywhere else in a mod, you replace that text with a variable that is noted as {{VariableName}}. Most variables that we replaced here are self explanatory: We replace various text (strings) and numbers (integers and floats). The interesting part here are the two SCS string (text) array variables: info[] and overrides[]. As you can see, we completely replaced them, not just the part where they hold data. That's because MS2 has a built-in variable type to handle them, as we don't know how many lines of data we need to have them hard-coded in the template.

Now that we have our *.sii definition file ready, we can edit our template.xml file. Use the same text editor as you did earlier. We'll start by adding basic mod template data:

<Template xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScsTemplate">
  <TemplateName>Simple engine</TemplateName>
  <TemplateBaseFolder>\Data\ModProjects\ETS2\Templates\SimpleEngine\</TemplateBaseFolder>
  <TemplateDescription>Create a truck engine mod</TemplateDescription>
  <TemplateGroup>Truck Technology</TemplateGroup>
</Template>

By doing this, the mod template should already show up in MS2.(Start a new project to reload templates.)

If you click this template, it will get added to the project, but selecting it in the template list won't open a variable edit window. That's simply because we haven't defined any variables in the template. We can take a look back to our SimpleEngine.sii file to see what variables we need to define. Mods Studio 2 supports different variable types that represent different types of data and give the user different ways to enter this data. Here's an overview of variables that we have used in our *.sii definition file; Note that we added an engine icon variable that will allow our users to pick a workshop/garage UI icon for their mod.

Variable name Variable type
InternalName StringVariable
Truck ScsVehicleVariable
EngineName StringVariable
EnginePrice IntegerVariable
EngineUnlock IntegerVariable
EngineTorque IntegerVariable
EngineRpmLimit
IntegerVariable
EngineVolume
FloatVariable
EngineAdbluePowerLimit
FloatVariable
EngineInfo
ScsStringArrayVariable
EngineOverrides
ScsStringArrayVariable
EngineIcon ScsIconVariable


Different variable types have different properties that affect their behaviour. Our documentation will soon be expanded with details about these specifics.

Let's add all these variables to our template file using the XML notation. Here's how our file should look after we're done with this step:

<Template xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScsTemplate">
  <TemplateName>Simple engine</TemplateName>
  <TemplateBaseFolder>\Data\ModProjects\ETS2\Templates\SimpleEngine\</TemplateBaseFolder>
  <TemplateDescription>Create a truck engine mod</TemplateDescription>
  <TemplateGroup>Truck Technology</TemplateGroup>
  <Variables>
    <Variable xsi:type="ScsVehicleVariable">
      <Name>Truck</Name>
      <Group>truck</Group>
      <Text>Truck</Text>
      <VehicleType>AllTrucks</VehicleType>
      <Game>ETS2</Game>
    </Variable>
    <Variable xsi:type="StringVariable">
      <Name>InternalName</Name>
      <Group>basic</Group>
      <Text>Engine Internal Name</Text>
    </Variable>
    <Variable xsi:type="StringVariable">
      <Name>EngineName</Name>
      <Group>basic</Group>
      <Text>Engine Name</Text>
    </Variable>
    <Variable xsi:type="IntegerVariable">
      <Name>EnginePrice</Name>
      <Group>basic</Group>
      <Text>Engine Price</Text>
    </Variable>
    <Variable xsi:type="IntegerVariable">
      <Name>EngineUnlock</Name>
      <Group>basic</Group>
      <Text>Unlock At Level</Text>
    </Variable>
    <Variable xsi:type="IntegerVariable">
      <Name>EngineTorque</Name>
      <Group>basic</Group>
      <Text>Engine Torque</Text>
    </Variable>
    <Variable xsi:type="IntegerVariable">
      <Name>EngineRpmLimit</Name>
      <Group>basic</Group>
      <Text>Engine Rpm Limit</Text>
    </Variable>    
    <Variable xsi:type="FloatVariable">
      <Name>EngineVolume</Name>
      <Group>basic</Group>
      <Text>Engine Volume (liters)</Text>
    </Variable>    
    <Variable xsi:type="FloatVariable">
      <Name>EngineAdbluePowerLimit</Name>
      <Group>basic</Group>
      <Text>Engine Adblue Power Limit</Text>
    </Variable>        
    <Variable xsi:type="ScsStringArrayVariable">
      <Name>EngineInfo</Name>
      <Group>basic</Group>
      <Text>Engine Info</Text>
      <InternalName>info</InternalName>
    </Variable>
    <Variable xsi:type="ScsStringArrayVariable">
      <Name>EngineOverrides</Name>
      <Group>basic</Group>
      <Text>Engine Overrides</Text>
      <InternalName>overrides</InternalName>
    </Variable>
    <Variable xsi:type="ScsIconVariable">
      <Name>EngineIcon</Name>
      <Group>icon</Group>
      <Text>Icon</Text>
      <ChildVariables>
        <Variable xsi:type="StringVariable">
          <Name>OverlaySource</Name>
        </Variable>
      </ChildVariables>
      <AllowedExtensions>
        <string>png</string>
        <string>dds</string>
      </AllowedExtensions>
    </Variable>
  </Variables>
</Template>
Variables can have ChildVariables. Any variable can have or be a a child variable. Support for rendering of child variables in the MS2 editor UI is limited and will be expanded as necessary. Consult specific variable type docs to see common use cases for child variables. Child variable placeholder looks like this: {{EngineIcon.OverlaySource}} It's a dot delimited parent/child variable names.

Once you add the above variables to your template file, run MS2 and start a new project. Add your new template to it -  now when you select the template in the list, MS2 will render the editor for it. However, the mod export still wouldn't do anything. We'll deal with that in the next step.

So, now we "told" MS2 how and what information we need to build a mod, and what to display in the editor. The next step is to tell MS2 how to turn this information into a working mod. We do this by adding Actions into our template file. As with variables, MS2 has many predefined actions that we can use to make a mod. Here's a list of actions we need to make a working engine mod:

Action Parameters (details) Description

CreateDirectory


Paths:

\def\vehicle\truck\{{Truck}}\engine
\material\ui\accessory\

This action takes one or more string parameters called "Paths". MS2 than creates all these folders in the mod structure.
Note that you can use variables with the {{VariableName}} notation in these paths as well. For our example we need a folder where our new engine definition will reside. The second path is the default folder for workshop icons, where our new engine icon will reside as well.

CopyFile


Paths:
From: SimpleEngine.sii
To: \def\vehicle\truck\{{Truck}}\engine\{{InternalName}}.sii
We'll define one CopyPair (a set of From/To paths) of paths to copy. "From" path is relative to the mod template folder, thus we only need to define the file name. "To" path is just like the one in the previous CreateDirectory action. This action will just take our SimpleEngine.sii file that we made earlier and copy it into the engine definition folder that was created by the previous action. It will also change the filename of the copied file to the value of our InternalName variable. You can define multiple CopyPair sets to be executed by one CopyFile action.

UpdateTextVariables


Paths:
\def\vehicle\truck\{{Truck}}\engine\{{InternalName}}.sii
The definition file that we copied in the previous action still contains all the variable placeholders. This action will go trough them one by one and replace them with their proper values. Multiple paths are supported.

ImportImage


Source: {{EngineIcon}}

Destination: \material\ui\accessory\{{InternalName}}.dds
OverlaySource: {{EngineIcon.OverlaySource}}
OverlayTransparency: 0.4
OutputFormat - Format: Dds
OutputFormat - Preset: ScsIconImage

This action will take the icon that the user selected, and it will convert it to the proper output format that the game can recognize. In this case, we defined the output format to be a DDS file with a specific preset (ScsIconImage). If the user selected an overlay, we'll add it to the image with the defined transparency. Path to this overlay is stored in the dot-delimited notation of parent/child variable, in this case {{EngineIcon.OverlaySource}}.

GenerateTobjFile


FileName: \material\ui\accessory\{{InternalName}}.tobj
Content: /material/ui/accessory/{{InternalName}}.dds
TobjType: UIIcon

This action will generate the required TOBJ file for our workshop icon. Filename defines where the file name of the newly created tobj file in the mod structure. Content is the path that is stored inside of the TOBJ file and it should point to the DDS image file of the icon that we created in the previous action. Note that content path contains slashes unlike other paths which contain backslashes. We also define a preset for the TOBJ file to be UIIcon.

WriteTextFile


FileName: \material\ui\accessory\{{InternalName}}.mat
TextLines:
material : "ui"
{
texture : "{{InternalName}}.tobj"
texture_name : "texture"
}

Lastly, we need to create the accompanying *.mat file for our workshop icon. This action creates a file specified by FileName and writes plain text into it. Text to write is specified in TextLines. Indeed, variable placeholders can be used in the TextLines content and they will get replaced with their values automatically prior to being written into the file. This action is meant for smaller pieces of text, as it's more convenient to use template files like we did with the *.sii file.

After we write all of this in a proper XML format, our mod template xml file will look like this:

<Template xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScsTemplate">
  <TemplateName>Simple engine</TemplateName>
  <TemplateBaseFolder>\Data\ModProjects\ETS2\Templates\SimpleEngine\</TemplateBaseFolder>
  <TemplateDescription>Create a truck engine mod</TemplateDescription>
  <TemplateGroup>Truck Technology</TemplateGroup>
  <Variables>
    <Variable xsi:type="ScsVehicleVariable">
      <Name>Truck</Name>
      <Group>truck</Group>
      <Text>Truck</Text>
      <VehicleType>AllTrucks</VehicleType>
      <Game>ETS2</Game>
    </Variable>
    <Variable xsi:type="StringVariable">
      <Name>InternalName</Name>
      <Group>basic</Group>
      <Text>Engine Internal Name</Text>
    </Variable>
    <Variable xsi:type="StringVariable">
      <Name>EngineName</Name>
      <Group>basic</Group>
      <Text>Engine Name</Text>
    </Variable>
    <Variable xsi:type="IntegerVariable">
      <Name>EnginePrice</Name>
      <Group>basic</Group>
      <Text>Engine Price</Text>
    </Variable>
    <Variable xsi:type="IntegerVariable">
      <Name>EngineUnlock</Name>
      <Group>basic</Group>
      <Text>Unlock At Level</Text>
    </Variable>
    <Variable xsi:type="IntegerVariable">
      <Name>EngineTorque</Name>
      <Group>basic</Group>
      <Text>Engine Torque</Text>
    </Variable>
    <Variable xsi:type="IntegerVariable">
      <Name>EngineRpmLimit</Name>
      <Group>basic</Group>
      <Text>Engine Rpm Limit</Text>
    </Variable>    
    <Variable xsi:type="FloatVariable">
      <Name>EngineVolume</Name>
      <Group>basic</Group>
      <Text>Engine Volume (liters)</Text>
    </Variable>    
    <Variable xsi:type="FloatVariable">
      <Name>EngineAdbluePowerLimit</Name>
      <Group>basic</Group>
      <Text>Engine Adblue Power Limit</Text>
    </Variable>        
    <Variable xsi:type="ScsStringArrayVariable">
      <Name>EngineInfo</Name>
      <Group>basic</Group>
      <Text>Engine Info</Text>
      <InternalName>info</InternalName>
    </Variable>
    <Variable xsi:type="ScsStringArrayVariable">
      <Name>EngineOverrides</Name>
      <Group>basic</Group>
      <Text>Engine Overrides</Text>
      <InternalName>overrides</InternalName>
    </Variable>
    <Variable xsi:type="ScsIconVariable">
      <Name>EngineIcon</Name>
      <Group>icon</Group>
      <Text>Icon</Text>
      <ChildVariables>
        <Variable xsi:type="StringVariable">
          <Name>OverlaySource</Name>
        </Variable>
      </ChildVariables>
      <AllowedExtensions>
        <string>png</string>
        <string>dds</string>
      </AllowedExtensions>
    </Variable>
  </Variables>
  <BuildActions>
    <Action xsi:type="CreateDirectory">
      <Paths>
        <string>\def\vehicle\truck\{{Truck}}\engine</string>
        <string>\material\ui\accessory\</string>
      </Paths>
    </Action>
    <Action xsi:type="CopyFile">
      <Paths>
        <CopyPair>
          <From>SimpleEngine.sii</From>
          <To>\def\vehicle\truck\{{Truck}}\engine\{{InternalName}}.sii</To>
        </CopyPair>
      </Paths>
    </Action>
    <Action xsi:type="UpdateTextVariables">
      <Paths>
        <string>\def\vehicle\truck\{{Truck}}\engine\{{InternalName}}.sii</string>
      </Paths>
    </Action>
    <Action xsi:type="ImportImage">
      <Source>{{EngineIcon}}</Source>
      <Destination>\material\ui\accessory\{{InternalName}}.dds</Destination>
      <OverlaySource>{{EngineIcon.OverlaySource}}</OverlaySource>
      <OverlayTransparency>0.4</OverlayTransparency>
      <OutputFormat>
        <Format>Dds</Format>
        <Preset>ScsIconImage</Preset>
      </OutputFormat>
    </Action>
    <Action xsi:type="GenerateTobjFile">
      <FileName>\material\ui\accessory\{{InternalName}}.tobj</FileName>
      <Content>/material/ui/accessory/{{InternalName}}.dds</Content>
      <TobjType>UIIcon</TobjType>
    </Action>
    <Action xsi:type="WriteTextFile">
      <FileName>\material\ui\accessory\{{InternalName}}.mat</FileName>
      <TextLines>
        <string>material : "ui"</string>
        <string>{</string>
        <string>	texture : "{{InternalName}}.tobj"</string>
        <string>	texture_name : "texture"</string>
        <string>}</string>
      </TextLines>
    </Action>
  </BuildActions>
</Template>

And that's it! If you now start a new project, you'll be able to create engine mods for ETS2. Here you can see a working engine mod in Euro Truck Simulator 2:

What's next?

Notice how the workshop icon is a bit too big and doesn't show info? And, how our Torque in the right side says "A lot of fun"? :) Well, these are little kinks that we could improve in our mod template by completely removing the Icon variable, so our users couldn't select their icons. We can replace it with the default ETS2 engine icon instead. (Or, we even might offer the user the small engine icon as a default option.) Also, we could remove the EngineInfo variable and return the 3-line info template back into our *.sii template file. We already have power (hp) and torque (Nm) numbers, so we could just add two more number (integer) variables that would ask for From and To torque RPM range. In that way we could "force" our users to create a mod that is completely in-line with SCS Software engine standards. But all of this is for another day... We successfully made a mod template, and that was the goal of this tutorial.

Thanks for reading!