REQUIREMENTS

Basic understanding of Unity. If you have none, I recommend doing some beginner tutorials.
Experience with 3D modelling software. This is not something I will be covering. The best free 3D program is Blender, there are various paid (and fairly expensive) options. You need to be able to export FBX files since that's what Unity reads.
I STRONGLY recommend installing Unity Explorer and exploring the game with it to learn how CMS2021 looks from the inside. Explore what the garage scene contains, explore the structure of a complete car.
I also recommend extracting existing parts and assemblies from the game files to use as reference. This can be done with Asset Studio or Asset Ripper


MOD FILE STRUCTURE

All mod content goes into tkaftermarket\content\ folder
There is one "global" folder with, guess what, global content inside
Every content package goes into its own subfolder in the content folder
Every content package folder must be structured like this:
\asset bundles\ - contains all asset bundles for this package
\parts\ - contains all parts text files, both standard and tuned
\assemblies\ - contains all part assemblies text files (what you select under Parts in the car editor)
\suspensions\ - all suspension assemblies text files
\engines\ - all engine assemblies text files


CREATING PARTS


CREATING PART MODELS
Begin by reading the guide on creating bonus parts. Install and setup Unity as described (must have correct Unity version!). No need to use the exporter script, use this instead - https://learn.unity.com/tutorial/introduction-to-asset-bundles

The part model creation process is basically the same, except a new part prefab needs to have a MeshCollider component.
When it comes to materials, you have several options:
- use game materials; there are several generic materials in the game that are not part-specific. If you want to use those, simply name your material as one of them and the mod will convert it to the game material when it loads your part(s). List of these materials can be found in materialsources.txt file. If you know what you're doing you can add more parts to this list so the mod caches additional materials.
- use your own materials with your own textures. In this case it's recommended to be familiar with creating Unity materials. NOTE that your materials will be converted to game shader by the mod in order to have condition-based rust. Your material typically should include base map, normal map and what is called "mask map" in Unity (for HDRP) but in the game shader is called "packed map". Read about it here - https://docs.unity3d.com/Packages/[email protected]/manual/Mask-Map-and-Detail-Map.html but NOTE that the "packed map" used by the game shaders is NOT a direct copy of the mask map. Instead the packedmap looks like this:
- red channel: metallic
- green channel: AO
- blue channel: shininess
- alpha channel: make it 100% white
I use this tool to create packed maps - https://www.reddit.com/r/Unity3D/comments/glkvp2/i_made_another_mask_map_packer_for_hdrp/
So what you must do is assign your maps as described above, create the "mask map", assign it to the mask map slot and then when my mod reads your material it will convert it to a game material and properly assign the maps where they belong. Since the "mask map" is packed for the game shader, it won't look correctly in Unity, just ignore this.
- create a game material variant; the way this works is you create a material named like the game material but with a (something) suffix. Also include a MaterialVariant keyword in the text file (explained below). Then the mod will copy the game material and use your material only as instructions on what to change. For example, if you want to use the game steel material but with a red color, you name your material "stal (red)" (space between "stal" and "(red)" is important!) and set your material base color to red (1, 0, 0, 1), and assign NO textures to it. Then the mod will load the game stal material and only change its base color to red. This way you can reuse the game textures without making your own and keep your mod package size smaller.

PART NAMING
 I recommend that you name your parts (both prefabs in Unity and part IDs described below) with your username as prefix to help avoid conflicting names with other mods. I
also recommend that the part name is sufficiently descriptive. All parts
should be named with lowercase characters and _ instead of spaces.
Example part name: tk3r_good_part_name

PART PROPERTY INFO

Once you have your model prepared in Unity and correctly set up and built your asset bundle (it must have .asset extension), you need to fill out a text file for the part. Use one of the included part files for guide, and use the included resources\parts.csv dump file with vanilla part data for reference.

- the first section contains asset information
Asset Data:
AssetBundleName= // the name of the actual asset file, without the .asset extension (so if you file is called mynewpart.asset, enter mynewpart here)
AssetName= // the name of the actual prefab asset inside the file, so if the part prefab is called mynewpart.prefab, enter mynewpart here
Reference= // this is the part name of the vanilla part that's most like your new part, so if you're making a new brake rotor, you could enter the part id of the vanilla regular brake rotor here
MaterialReference= // if your part has its own material / textures, leave this empty (or omit the line entirely). Otherwise enter here the part (vanilla or mod, either is OK) that should be the source for your part's material. This way you can reuse materials between parts, or if your part is a slightly modified vanilla part, you can just use the vanilla material

- this section contains part information. PartProperty is how the class that stores part information in the game is called
PartPropertyData:
ItemID= // your part id in the game
Price= // price in store
PartGroup= // see parts.csv and get the right value from there
ShopGroup=Brakes // Engine, Brakes, Suspension etc
ExamineGroup= // see parts.csv and get the right value from there
RepairGroup= // 0 means not repairable, 1-5 corresponds to player repair skill
SpecialGroup= // see parts.csv and get the right value from there
IsBodyPart=FALSE // true for body panels, glass etc but those are NOT tested and I believe they only come with car packages
LocalizedName= // human readable name of the part in the game, for now English is standard but you can put here anything
Brand= // use one of the vanilla brands or a new brand, I believe QoL mod allows to make new brands
ShopName=TuningShop // for now the mod only supports tuned parts
CarID= // leave empty for now
IsMod=false // set to true to get a "mod" icon on your part
CanPaint=true // can the part be painted; for now this doesn't do much because painting is material-restricted

- for now we don't do anything with this info but suggest to copy it from the parts.csv file for future use
Fault Data:
ItemFaultDifficultMod=0.5
ItemFaults=brakesGeneral/

- tuning data section
Tuning Values:
TunedPartFor= // enter here the part id of the vanilla part that your new part will be replacing
TunedPower= // power tuning added in %
TunedGrip= // grip tuning in %, unknown if this does anything
TunedBrakes= // brake tuning added in %
TunedMass= // unknown if this does anything
TunedSteer= // unknown if this does anything

- only include this section if the part is a parent (such as control arm being parent of two bushings or brake caliper being parent of brake caliper piston. See part groups.txt file for all vanilla groups and copy the information from there
Child Part Data:
part1= // part id of first vanilla part that is child of this part
part2= // part id of second vanilla child part

REPLACING VANILLA PARTS
If you want to replace a vanilla part - change the model or just the material, then name your part (prefab asset as well as part text file name) REPLACEvanillapartname. Then in the part text file include the following keywords:
ReplaceMesh=true if you want to replace the part model (mesh)
ReplaceMaterials=true if you want to replace the material (note you need both this and mesh set to true if you want to use your own model with its own new material); this will overwrite completely the materials array of the original part so you better know what you're doing if you want to override an existing mesh's materials
MergeMaterials=true if you want to replace only some of an existing mesh's materials. The mod will compare the materials arrays of both existing and mod mesh and if a new material's name is the same as a game material, it will use the game material, but if it cannot find a game material then it will use the new material
MaterialVariant=true if you want to create a variant of existing material (such as darker/lighter steel or different color etc)


CREATING PART ASSEMBLIES

PART ASSEMBLY STRUCTURE
Parts (with capital P), Suspensions and Engines are part assemblies. This is what you can select and move in the car editor. So, Parts/Suspensions/Engines are made of parts (lowercase p) - the items that you can buy in the shops. Creating and adding parts we discussed above, now we will talk about assemblies. Fundamentally, all three types of part assemblies have the same structure, they just go in different object lists in the game engine. That's why we put them in different folders in the mod content packs. Parts and Suspensions have identical structure, Engines have additional specialized empty objects.
Part and Suspension names must start with #. The prefab names inside the asset bundles must start with #, however the text files defining them do not need to start with #. An assembly prefab made of thispart and 2 x thatpart must look like this:
#MyPartAssembly
   thispart(0)
   thatpart(0)
   thatpart(1)
#MyPartAssembly is the base assembly prefab which is an empty gameobject. All parts are children of this empty gameobject. It needs to have a BoxCollider component that should be roughly sized to fit the overall assembly.
Thispart and thatpart must be instances of existing part prefabs. Note that the mod will replace them with the part prefabs anyway so if you make any changes to the gameobjects in the assembly prefab they'll be lost. Only the transform data (position, rotation, scale) and name will be kept.

MOUNTS
Nuts and bolts are called mounts in the game. Adding them is fairly easy, you just need to get some from existing assemblies to use as reference. The mod will replace them with the actual prefabs from the game resources. Mounts for part thispart(0) inside the assembly prefab must be made children of an empty gameobject called thispart(0)_mounts, and must be named with the same (0), (1) etc suffix. It is important that other than the (0...) suffix you keep the original mount names exactly as they are so that the mod can load the correct bolt/nut from the game resources. So let's expand our earlier example to include mounts:
#MyPartAssembly
   thispart(0)
   thatpart(0)
   thatpart(1)
   thatpart(1)_mounts // empty gameobject
      bolt1(0)
      bolt1(1)

TEMPLATES
It would be too much work to recreate all the complex part assemblies from scratch, especially engines, so I have designed the mod to be able to read an existing part assembly and only add/remove parts as instructed. This is how it's done:
- import an existing assembly to use as reference (you could go without one but then you must REALLY know what you're doing)
- name it as your new assembly
- add an empty GameObject and name it TEMPLATE=ExistingAssembly, where ExistingAssembly is the name of the vanilla assembly you want to use as base.
- add your new parts the same way you would add them to a new assembly, except each new part must have an ADD= prefix (so, to add thispart(0), name it ADD=thispart(0)). The same applies to _mounts, except you do NOT need to add ADD= to each nut/bolt name, only to the _mounts parent empty GameObject.
- any parts that you want to remove from the template you must rename by adding REMOVE= as prefix.
- once you're done with setting up all keywords, you can delete all parts that will not be changed. This will save space, since you're basically only creating instructions for the mod how to put together your part assembly.

REPLACING ASSEMBLIES
Works exactly the same as replacing parts: name your assembly REPLACEExistingAssembly where ExistingAssembly is the name of the vanilla assembly you want to replace.

PART DEPENDENCY
This defines how parts interact, which parts block which, which go together as a group.
Part dependency data section is defined with these keywords
PartDependencyDataSTART
....
PartDependencyDataEND

Each part dependency record is formatted like this



UnblockOnUnmount - this means what parts are unblocked when the part in [ ] is removed. In other words, what parts are blocked by this part.
UnblockOnUnmountNames - this is the same except it allows connections to other assemblies. UnblockOnUnmount only works for parts in the same assembly, whereas the syntax in UnblockOnUnmountNames includes the name of the other assembly that the unblocked part is in. Example:
UnblockOnUnmountNames=RCSusp|tk3r_new_suspension_part - this means unblock tk3r_new_suspension_part in RCSusp (Rear Center Suspension)
UnmountWith - this means what parts unmount together with the part in [ ], for example a piston unmounts together with piston rings
UnmountWithSeparate - set to true or false; this means whether the part that was specified above is separated from the part in [ ] when unmounted. Pistons get separated from rings however shocks are not separated from springs / strut mounts.

Part Groups
There are several "part groups" in the game:
- strut assemblies
- control arms with bushings
- brake calipers with brake pistons
If you create a new assembly of this type the mod will automatically create a part group from parts which have a parent-child relationship. Meaning, if a GameObject named part2 is a child of GameObject named part1, the mod will create a group of the two parts and populate the necessary information when it creates the game components.

GLOBAL MATERIAL OVERRIDES
This allows you to change the default look of whole bundles of parts as if they are painted. I have used it to make all basic suspension parts look like they are painted black like in real life. The material overrides are found in content\global\material overrides. Look at the text files inside, everything is self-explanatory. Keywords are partial or complete names of parts from the game that will get their materials overridden. Material override properties work like this: the original material of the part is loaded and any material override properties that are defined are changed. E.g. if you set a red base color and the base material of the part is steel, the result is red steel part.

Article information

Added on

Edited on

Written by

tk3r

0 comments