Teardown

Teardown

Not enough ratings
[YLVF Toolkit] Vehicle Data Setup Tutorial
By YuLun
Tutorial for using YLVF Toolkit to setup your vehicle pack for the new YLVF customizable vehicle spawning feature
   
Award
Favorite
Favorited
Unfavorite
Basic Info
This is a tutorial for my YLVF Toolkit, which is a NON-FUNCTIONAL* mod provides essential files required to setup your own vehicle packs to use the latest YLVF spawning feature.

If you DOES NOT make vehicles (which means using game editor to create, massively modify or recreate any vehicles), this tutorial is useless and you're free to leave.

If you are new to vehicle making, this tutorial is not very suitable for you.

*: Non-functional means: by simply subscribing to this mod, this mod would neither be manually/automatically activated nor can be activated by any other mod via any method.
Installation
This section would tell you how to install essential files to your vehicle folder and add your vehicle pack to list
  1. Subscribe to YLVF Toolkit
  2. After this mod have been downloaded, click 'Make local copy'

  3. Open local folder of copied Toolkit

  4. After you opened the folder, you should see following files

  5. Drag (same as copy paste) the YLVF folder and YLVFdata.lua into your vehicle pack's folder
    for example: if you have a pack with main folder called 'My Vehicle Pack', open that folder and directly paste inside
    (picture uses my Misaka Vehicle Pack as reference)

  6. Open your vehicle pack's spawn.txt file
    (find tutorials for creating spawn.txt file if can't make sure, I'm not gonna teach you this here)
  7. At the first line add this
    YLVF/YLVF.xml : YLVF/DUMMY
    so it should be something like this

  8. After done everything above correctly, you should see an 'Unnamed Pack' in list after you open the YLVF spawn panel. Click on it would show a blank spawn panel with no title.

  9. Now installation is done, you can start setup your vehicles
Vehicle Data
In this section, I would assume you know basics of Lua language therefore I will skip some very basic knowledge (e.g.: declaring variables, formatting & syntax). If you're not familiar with this I suggest you to find some tutorial about Lua fist.

THIS SECTION IS NOT EASY TO UNDERSTAND QUICKLY therefore I would break it down and explain as detail as possible. This is also the reason why it's very long.
| - Basic
In this section, I will only explain the very basic context of functions used to setup vehicle data. Check 'Advanced' section for more info
- - | - Pack Title
Obviously you can change title of pack :D
  1. Open YLVFdata.lua inside your vehicle pack (I'm using VS Code therefore appearance might be different from what you see)

  2. Below the dashed line, you can see this
    PACKNAME = "" PACKAUTHOR = ""
    These are name and author of vehicle pack which would shown on spawning panel.
    Type in name and author to change
    PACKNAME = "Tutorial Sample" PACKAUTHOR = "YuLun"
- - | - Adding Vehicle Models
In reality, almost all vehicle manufactured would belong to one base model, say 'Toyota Land Cruiser'. The dealership would give you available options (like the pic below) so you can choose the one you want.


Similarly, here we also separate vehicles according to models and then provide options


So How to add a new vehicle model?
  1. Still inside YLVFdata.lua, start a new line at bottom, type this function to add a new vehicle
    NewVehicle()


    Now you can see a new vehicle model is added


  2. By default, the name is 'unnamed' with no description for it, you can change this to whatever you want.
    This function have two optional parameters
    NewVehicle(name, desc) name (string, optional) - name of vehicle model desc (string, optional) - description of model

  3. To finish current vehicle section, you need another function
    FinishVehicle()


    ⚠️REMEMBER⚠️
    • This function is required by all vehicles you added.
    • You are NOT ALLOWED to use NewVehicle() function again if you didn't finish the current one. If you do, errors may occur and vehicle data may be missing.
    • You are NOT ALLOWED to use FinishVehicle() function WITHOUT calling NewVehicle() function previously. If you do, errors definitely would occur.

    If you're using a text editor (e.g.: VS Code or Notepad++), you may treat these functions as brackets, so you can collapse it if you don't want to scroll hundreds of lines

    Collapsed /\ vs Expanded \/
- - | - Adding Cabins
This term is more related to trucks, it means the inside space in a truck where driver is seated. But here this term would represent all similar structures on any vehicles, you can simply recognise this as a vehicle without chassis.

⚠️YOU NEED AT LEAST 1 CABIN FOR EACH VEHICLE⚠️

How to add a cabin to vehicle?
  1. Add this function between NewVehicle() and FinishVehicle()
    AddCabin()


    Now you can see an 'unnamed' cabin in list


  2. This function have 4 parameters, you can choose to not add any however this would simply make this cabin useless. If you trying to spawn with it, errors may occur.
    AddCabin(name, desc, XMLstring, blacklist) name (string) - name of this cabin desc (string) - description of this cabin XMLstring (string) - xml data containing cabin data, you can copy from your level xml file or prefab xml file directory, multiple lines of string requires a backslash '\' to connect different lines blacklist (table, optional) - blacklist for this cabin, not recommended to add in order to avoid self-locking
- - | - Add Chassis
Simply this is the chassis of vehicle.
This section also carries vehicle parameters (NOT IN PREVIOUS CABIN SECTION).

⚠️YOU NEED AT LEAST 1 CHASSIS FOR EACH VEHICLE⚠️

How to add a chassis to vehicle?
  1. Add this function between NewVehicle() and FinishVehicle()
    AddChassis


    Now you can see an 'unnamed' chassis in list


  2. This function have 7 parameters, you can choose to not add any however this would simply make this chassis useless. If you trying to spawn with it, errors may occur.
    AddChassis(name, desc, XMLstring, vehicleParam, bodyOffset, blacklist, tags, bodytags) name (string) - name of chassis desc (string) - description of chassis XMLstring (string) OR XMLlist (table) - chassis data of vehicle vehicleParam (list) - list of all vehicle data, start from sound, same order as in editor bodyOffset (string) - offset of vehicle main body entity related to vehicle entity blacklist (table) - blacklist for this chassis tags (string) - additional tags required (e.g.: reversebeep) bodytags (string) - additional tags required
- - | - Add Body
Again, this term is more related to trucks, which (mostly) represents the payload portion of vehicle which is independent of cabin. Therefore this section is NOT required by all vehicles.

Adding a body to vehicle
  1. Add this function between NewVehicle() and FinishVehicle()
    AddBody()


    Now you can see an 'unnamed' body in list


  2. This function have 6 parameters, you can choose to not add any however this would simply make this body useless. If you trying to spawn with it, errors may occur.
    AddBody(name, id, desc, XMLstring, blacklist, replace) name (string) - name of body id (string) - internal id for compatibility checking, works along with blacklist desc (string) - description of body XMLstring (string) - body data of vehicle blacklist (table) - blacklist for this body replace (string, optional) - replace searching id. If not filled in, body data is added to end of vehicle data, otherwise is searches for target and replace it when found
- - | - Add Paint
No painting is also a paint, so obviously...

⚠️YOU NEED AT LEAST 1 PAINT FOR EACH VEHICLE⚠️

Adding a paint
  1. Add this function between NewVehicle() and FinishVehicle()
    AddPaint()


    Now you can see an 'unnamed' paint in list, also, at bottom of list there's a color selection panel shows up automatically


  2. This function have 5 parameters, you can choose to not add any however this would simply make this paint useless. If you trying to spawn with it, errors may occur.
    AddPaint(name, desc, XMLtable, paletteNum, paintID) name (string) - name of paint desc (string) - description of paint XMLtable (table) - FORMATTED paint xml data paletteNum (number, optional) - max number of colors used by this paint, must be positive integer paintID (string) - internal id used to pick the vox object used
- - | - Add Component
Vehicles are machines, which are consist of components. So you can replace / remove / add components to a vehicle, or does nothing if you prefer the original design.

Adding a component
  1. Add this function between NewVehicle() and FinishVehicle()
    AddComponent()


    Now you can see an 'unnamed' component in list


  2. This function have 6 parameters, you can choose to not add any however this would simply make this component useless. If you trying to spawn with it, errors may occur.
    AddComponent(name, id, desc, XMLdata, blacklist, replace) name (string) - name of component id (string) - internal id for compatibility checking, works along with blacklist desc (string) - description of component XMLdata (string OR table) - string of component data OR FORMATTED list of data replace (string) - replace searching id. If not filled in, component data is added to end of vehicle data, otherwise is searches for target and replace it when found
- - | - Add Packed Vehicle
After V2.0 update, you can add vehicle presets into your vehicle pack and upload to workshop. This could be helpful to those are not very familiar with YLVF spawning, or you have a fantastic vehicle design want to share.

Adding a packed vehicle
  1. Add this function outside NewVehicle() and FinishVehicle()
    AddPackedVehicle()

    Now you can see an 'unnamed' vehicle preset in 'saved vehicles' list

  2. This function have 4 parameters, but only description (desc) can be optional
    AddPackedVehicle(name, desc, id, shortcode) name (string) - name of vehicle preset desc (string) - description of vehicle preset id (number) - internal id for vehicle models, first is 1, second is 2, etc. (This parameter might be ignored in future updates) shortcode (string) - string of shortcode data, generated by mod, of this vehicle present.
| - Advanced
In this section, I will explain parameters of each function more clearly, with samples provided
- - | - Functions
This section explains details of all functions used to add vehicle data
- - - - | - NewVehicle() & FinishVehicle()
NewVehicle()
This function is used to add a new vehicle model to list.

⚠️YOU MUST USE THIS FUNCTION ALONG WITH FinishVehicle()⚠️

-- Parameters --

This function have two parameters
NewVehicle(name, desc)
where
  • name - string
    Name of current vehicle model
    Default: "Unnamed" - string
    Max Length: 28 characters, forced clips to 28 if longer

  • desc - string
    Description of current vehicle model
    Default: "" - string (empty)
    Max Length: Suggested no longer than 80, does not clip if longer BUT have possibility to exceed boundaries

-- Sample --







FinishVehicle()
This function is used to finish the current vehicle model.

⚠️YOU MUST USE THIS FUNCTION ALONG WITH NewVehicle()⚠️

-- Parameters --

No Parameters

-- Sample --



- - - - | - AddCabin()
AddCabin()
This function is used to add a new cabin option to current vehicle.

-- Parameters --

This function have 4 parameters
AddCabin(name, desc, XMLstring, blacklist)
where
  • name - string
    Name of current vehicle cabin
    Default: "unnamed" - string
    Max Length: 28 characters, forced clips to 28 if longer

  • desc - string
    Description of current vehicle cabin
    Default: "" - string (empty)
    Max Length: Suggested no longer than 80, does not clip if longer BUT have possibility to exceed boundaries

  • XMLstring - string
    .xml formatted cabin data (same format as map's .xml files, which is not suggested)
    Default: "" - string (empty, but not recommended)

  • blacklist - table
    Formatted blacklist data
    Default: {} - table (empty, recommended to leave as default to avoid self-locking)
    Additional: see 'Formatting' section to check more details
- - - - | - AddChassis()
AddChassis()
This function is used to add a new chassis option to current vehicle.

-- Parameters --

This function have 6 parameters
AddChassis(name, desc, XMLstring OR XMLlist, vehicleParam, bodyOffset, blacklist, tags, bodytags)
where
  • name - string
    Name of current vehicle chassis
    Default: "unnamed" - string
    Max Length: 28 characters, forced clips to 28 if longer

  • desc - string
    Description of current vehicle chassis
    Default: "" - string (empty)
    Max Length: Suggested no longer than 80, does not clip if longer BUT have possibility to exceed boundaries

  • XMLstring - string
    .xml formatted cabin data (same format as map's .xml files, which is not suggested)
    Default: "" - string (empty, but not recommended)
    OR
    XMLlist - table
    This type of parameter ONLY get recognized when given
    .xml formatted cabin data (same format as map's .xml files, which is not suggested)
    Default: "" - string (fallback to XMLstring)

  • vehicleParam - table
    formatted vehicle parameters data, starts from vehicle sound
    Default: {} - table (empty, when not filled in would use default vehicle parameters)
    Additional: see 'Formatting' section to check more details

  • bodyOffset - string
    .xml formatted main body offset, order used same as game vector, unit in meters
    Default: "" - string (empty, when not filled in would use no offset: "0.0 0.0 0.0")
    Additional: see 'Formatting' section to check more details

  • blacklist - table
    Formatted blacklist data
    Default: {} - table (empty)
    Additional: see 'Formatting' section to check more details

  • tags - string
    Tags required by the vehicle ('YLVF' tag is automatically added so you don't need to)
    Default: "" - string (empty, when not filled in, only 'YLVF' tag is added)

  • bodytags - string
    Tags required by the vehicle ('nocull' tags is automatically added)
    Default: "" - string (empty, when not filled in, only 'nocull' tag is added)
- - - - | - AddBody()
AddBody()
This function is used to add new body option to current vehicle.

-- Parameters --

This function have 6 parameters
AddBody(name, id, desc, XMLstring, blacklist, replace)
where
  • name - string
    Name of current vehicle body
    Default: "unnamed" - string
    Max Length: 28 characters, forced clips to 28 if longer

  • id - string ⚠️not in use currently
    Internal id used for compatibility checking, works along with blacklist
    Default: "" - string (empty, when not filled in is recognized as universally compatible)
    Additional: see 'Formatting' section to check more details

  • desc - string
    Description of current vehicle body
    Default: "" - string (empty)
    Max Length: Suggested no longer than 80, does not clip if longer BUT have possibility to exceed boundaries

  • XMLstring - string
    .xml formatted cabin data (same format as map's .xml files, which is not suggested)
    Default: "" - string (empty, but not recommended)

  • blacklist - table
    Formatted blacklist data
    Default: {} - table (empty)
    Additional: see 'Formatting' section to check more details

  • repalce - string
    Internal searching label to replace specific sections of vehicle data
    Default: "" - string (empty, when not filled in would disable replacing and add body data to end of vehicle data, otherwise it searches for this label and replace it by body data if found)
    Additional: see 'Formatting' section to check more details
- - - - | - AddPaint()
AddPaint()
This function is used to add a new paint option to vehicle.

-- Parameters --

This function have 5 parameters
AddPaint(name, desc, XMLtable, paletteNum, paintID)
where
  • name - string
    Name of current vehicle paint
    Default: "unnamed" - string
    Max Length: 28 characters, forced clips to 28 if longer

  • desc - string
    Description of current vehicle paint
    Default: "" - string (empty)
    Max Length: Suggested no longer than 80, does not clip if longer BUT have possibility to exceed boundaries

  • XMLtable - table
    Formatted table of vehicle paint data
    Default: {} - table (empty, but not recommended)
    Additional: see 'Formatting' section to check more details

  • paletteNum - number
    Number of maximum colors can be used by this paint
    Default: 1 - number

  • paintID - string
    Internal id used to apply paint to vehicle data
    Default: "" - string (empty, but not recommended)
    Additional: see 'Formatting' section to check more details
- - - - | - AddComponent()
AddComponent()
This function is used to add new component option to current vehicle.

-- Parameters --

This function have 6 parameters
AddComponent(name, id, desc, XMLdata, blacklist, replace)
where
  • name - string
    Name of current vehicle chassis
    Default: "unnamed" - string
    Max Length: 28 characters, forced clips to 28 if longer

  • id - string
    Internal id used for compatibility checking, works along with blacklist
    Default: "" - string (empty, when not filled in is recognized as universally compatible)
    Additional: see 'Formatting' section to check more details

  • desc - string
    Description of current vehicle body
    Default: "" - string (empty)
    Max Length: Suggested no longer than 80, does not clip if longer BUT have possibility to exceed boundaries

  • XMLdata - string OR table
    Formatted data of this component
    Default: "" - string (empty, but not recommended)
    Additional: see 'Formatting' section to check more details

  • blacklist - table
    Formatted blacklist data
    Default: {} - table (empty)
    Additional: see 'Formatting' section to check more details

  • repalce - string
    Internal searching label to replace specific sections of vehicle data
    Default: "" - string (empty, when not filled in would disable replacing and add component data to end of vehicle data, otherwise it searches for this label and replace it by component data if found)
    Additional: see 'Formatting' section to check more details
- - - - | - AddPackedVehicle()
AddPackedVehicle()
This function is used to add new spawning-ready vehicle preset to vehicle pack.

-- Parameters --

This function have 4 parameters
AddPackedVehicle(name, desc, id, shortcode)
where
  • name - string
    Name of current vehicle preset
    Default: "Unnamed Vehicle" - string
    Max Length: 28 characters, forced clips to 28 if longer

  • desc - string (optional)
    Description of current vehicle preset
    Default: "" - string (empty)
    Max Length: Suggested no longer than 80, does not clip if longer BUT have possibility to exceed boundaries

  • id - number (integer)
    Internal id for the base model of this vehicle, which is defined by the order of NewVehicle() and FinishVehicle() functions
    Default: 1
    Additional: This parameter might be ignored in future updates

  • shortcode - string
    Short code, generated by mod, of this vehicle preset
    Default: Default value is HIGHLY NOT RECOMMENDED in this case. Please always give a short code
    Additional: Wrong code can generate a vehicle since there's a compatibility checking process before spawning
- - | - Formatting
This section would explain formatting and syntax requirements of some parameters mentioned in previous sections
- - - - | - Blacklist (blacklist & id)
id
In current version, the only two categories of parts using this are: body & components. And the body's id is not used for now, so you may assume only components are using this parameter.

The id is a string, in order to avoid interruption, please use letters, numbers and underline ' _ ' ONLY.
for example:
doorR_5 , aatg_r6 , P65_c_1

And id should be identical among all components inside the same category, although you CAN do something like this:
door_1 , doorR_b4 , adt_doorR_2
which is not difficult to see they share a common string: "door"

So what COULD happen is: your blacklisted "door" which you thought it represents all parts starts with "door", like this
blacklisted: door_1, door_2, door_3, door_a3, door_b...... not in list: cover_5, towH_4a, ar0, adt_door_9, doorR_2, doorR_3......

But in fact, this is what actually would happen:
blacklisted: door_1, door_2, door_3, door_a3, door_b...... AND adt_door_9, doorR_2, doorR_3...... not in list: cover_5, towH_4a, ar0......

The reason I didn't prevent this behaviour are:
  1. It's very complex to solve logically
  2. It's useful
Still the same example used above, you blacklisted "door".
But this time, you give id like this:
door1, door2, door3, doorP_2, doorP_3...... cover1, cover2, cover_L.... mirr_6, mirr_7, mirr_8.....
And all these components with "door" in id are incompatible, so you can use one common string to cover all of them, which is "door", instead of a long list of everything.



blacklist
This parameter is used to register the blacklist of current parts. Since we have 5 different categories of parts (cabin, chassis, body, paint, component) this list is divided into 5 sections as well.

This is a sample of expression of a blacklist which contains 4 categories(paint category not added in current version)
{p1 = {1, 4, 6}, p2 = {-4, 1}, p3 = {9}, p5 = {"wndd_3", "rebp", "rfrk_1"}
Looks like nightmare right? Let's break it down.
  1. Firstly you can clearly recognize this list is divided into 4 sections:
    p1 , p2 , p3 , p5
    Where each of these represent one category
    p1 : cabin p2 : chassis p3 : body p5 : component
    Blacklist is indexed so you don't have to add some section if current part is fully compatible with all parts in another category

    for example: this component is fully compatible with all cabins and bodies, so this is how the list might look like
    {p2 = {-2}, p5 = {"prtt_6", "wdef"}

  2. Now, you may notice a difference among these 4 sections of list:
    p1, p2, p3 only include numbers
    while
    p5 only include strings

    This is due to different logic of checking compatibility, you don't need to know exactly what logic is used, just remember:

    p1, p2, p3 only include numbers
    while
    p5 only include strings


  3. For p1, p2 & p3, they uses same logic, so they follow these rules:

    • Numbers inside the list are non zero integers ONLY
    • Absolute value of each integer represents the order of a part in its category
    • Positive integers means Not Compatible; if any is selected, current part can not be selected
    • Negative integers means Required; if any is not selected, current part can not be selected

    Lemme explain this
    Numbers inside the list are non zero integers ONLY
    This is easy to understand, integers only but not 0
    Absolute value of each integer represents the order of a part in its category
    So firstly, google "Absolute Value" if you don't know, here's not a math class.
    So the order of a part is given automatically when you add a new part. Different categories have independent orders and this is not affected by what order you're adding them, even mixing them up.
    Example 1:
    AddBody("body 1") -- its order is 1 AddBody("body 2") -- its order is 2 AddBody("another body 2") -- its order is 3 AddBody("body 3") -- its order is 4
    Example 2:
    AddBody("body 1") -- 1 in body AddBody("body 2") -- 2 in body AddChassis("Chassis") -- 1 in chassis AddBody("another body 2") -- 3 in body AddCabin("Classic") -- 1 in cabin AddChassis("New Chassis") -- 2 in chassis
    Since the order is given automatically, inserting a part half-way may mess up existing blacklist. Personally I recommend to group parts in categories and always add at end of each category.
    Example:
    AddBody("body 1") AddBody("body 2") AddBody("body 3") AddChassis("Regular Chassis") AddChassis("Enhanced Chassis") AddPaint("A cool paint") AddPaint("Another cool paint") AddPaint("A not that cool paint")
    Positive integers means Not Compatible; if any is selected, current part can not be selected
    So this
    {p3 = {1, 3}}
    means this part is not compatible with the first and the third part in body category. If either body is selected, this part is not compatible and would be crossed out, like this:

    Negative integers means Required; if any is not selected, current part can not be selected
    So this
    {p2 = {-2, -4, -7}}
    means this part is required to select either the second, forth or seventh part in chassis category. If none is selected, this part is not compatible and would be crossed out.

  4. For p5, it have another logic, here are the rules it follows:

    • Strings inside the list MUST be either 'a full id of a component' or 'a part of id of a component'
    • Strings represent Not Compatible ONLY
    • If there's a match found against this blacklist, the part would be marked as Incompatible

    So here I have to mention a little bit about logic.

    When checking, the blacklist of this part is compared with another internal list which consists of id of ALL selected components. Then if there's a match between the blacklist and internal list, the component is either crossed out or automatically remove the incompatible component(s) found when selected. The behaviour is determined by category of the part, you don't need to worry too much.

    To make it more clear: Imagine here's the internal list
    comp_1, comp_2, rfrak_1, mirr_3, mirr_6, aintk
    and here's blacklist
    {p5 = {"windd", "mirr_5", "aintk"}}
    so the result is: component with id "aintk" is found incompatible since they matched, while the rest are safe.

    Now you can add a '=' to mark other components as required, similar to negative numbers in p1, p2 and p3
    p5 = {"=rrckA", "mirr_5"} This means it requires components with id 'rrckA' to be compatible
- - - - | - xml data (XMLstring, XMLlist, XMLtable & XMLdata)
So, as you can see, XMLstring, XMLlist, XMLtable and XMLdata are different types of parameters, but they're all uses .xml format
- - - - - - | - XMLstring
The easiest one is XMLstring, it's just a string but in .xml format.

You can easily convert a line of xml content into Lua string by adding single quotes ( ' )
string = '<instance pos="0.5 0.2 0.0" file="MOD/prefab/optional_component.xml"/>'

for multiple line content, you need backslash ( \ ) to act as 'enter'
string = '\ <body tags="Ydoor nocull" pos="0.95 -0.3 -1.2" dynamic="true">\ <vox rot="0.0 -180.0 0.0" strength="2.5" file="MOD/vox/model.vox" object="mirrorR"/>\ <compound strength="2.5">\ <vox pos="0.0 0.2 0.0" file="MOD/vox/model.vox" object="doorR"/>\ </compound>\ </body>'
- - - - - - | - XMLlist
XMLlist is a table includes several .xml format strings, this parameter ONLY used by AddChassis() function so I will explain it together with function.
  1. Mostly, it's enough to use XMLstring for chassis therefore this parameter ONLY got recognized when it's given along with data

  2. The format is given as follow:
    Notice that where the id is counted from
    { "<......./>", -- main chassis data "<......./>", -- additional chassis data, id 1 "<......./>", -- additional chassis data, id 2 ... }
    Where each section of data are normal strings in .xml format (same as XMLstring)

  3. This parameter is designed to use with 'REPLACECHASSIS' keyword, although the main data is always added to vehicle.

    When adding chassis to vehicle, mod would search for all 'REPLACECHASSIS' keywords, when found, the id of the keyword is read, then mod would match the id with XMLlist and replace data included by keyword with matched chassis data

    For example:
    <compound> REPLACECHASSIS02 <voxbox .../> <vox .../> END <instance .../> </compound>
    so in this case id is '02', or 2 after converted to integer by mod
    the additional chassis data with id 2 would be added to the position and replace all original data included by keyword, in this case is
    <voxbox .../> <vox .../>
- - - - - - | - XMLtable
XMLtable is a table includes many .xml format strings, this parameter ONLY used by AddPaint() function so I will explain it together with function.
Understanding how vehicle paint works (obviously in this mod) would help you understand this section.
  1. We know that we can paint voxbox, by applying a color parameter.
    This is how this parameter is saved into xml files:
    color="0.5 0.45 0.33"
    So adding this into the voxbox data string would paint it. Here we add this data to end of string to avoid messing around other data. For example:
    original: '<voxbox size="21 21 54" brush="MOD/voxModel.vox" object="body"/>' added color: '<voxbox size="21 21 54" brush="MOD/voxModel.vox" object="body" color="0.5 0.45 0.33"/>'
    So you don't need to add 'color' to your string data.

  2. A string is not a table obviously, so you need to change it into a table.
    This might be a bit confusing but I will try to explain it clearly

    We use a keyword ' REPLACEPAINT ' to tell the mod where we need to paint. However, one word cannot represent multiple parts so we give a number at the end.

    So the actual keyword is like this:
    REPLACEPAINT01 REPLACEPAINT12 REPLACEPAINT28 REPLACEPAINT75 ...


    Now we have the keyword and a number, the mod can find the exact position to paint.
    However, the number is not given randomly, the number need to match with the XMLtable you given to the function AddPaint()

    This is how a XMLtable may looks like:
    { { '<voxbox .... />', '<voxbox .... />' }, { '<voxbox .... />' }, { '<voxbox .... />', '<voxbox .... />' } }
    Now this main table have three sub tables, each have a numerical index.
    This is what would happen when mod is painting a vehicle:

    1. Mod first find the keyword. If found, it continues, otherwise painting process is finished
    2. Mod would read the number behind keyword, so e.g.: 'REPLACEPAINT02' -> 02 -> 2.
    3. Then mod picks the second sub table and reads data inside, this step will be explained more detailed later.
    4. Now mod replace the keyword and number with data read and processed in previous step
    5. Go back to step 1 and repeat

    To make sure mod can always find the correct data, the number of sub tables must matches the max number behind any keywords.

  3. The second reason that table must be given in the format mentioned above is related to number of colors of a paint.

    This framework is different from normal voxbox painting trick which is like the rushed made vanilla vehicle in version 0.9.6, if you don't know, ask it on official discord's #modding-discussion channel similar to adding a color filter to model, which would make a red model purple when you trying to paint it blue.
    So I split up vox models into purely colorless black and white objects, then compound them together (ask someone if you don't know about compound)
    Now we need a color for each separated objects, that's the reason why there's a parameter paletteNum in AddPaint() function. That parameter's duty is telling mod how many colors this paint needs

    Now have a closer look into these sub tables (a sample)
    { '<voxbox .... />', '<voxbox .... />', '<voxbox .... />', '<voxbox .... />' }
    There're 4 strings inside, let's assume that's the maximum for this paint, so paletteNum would be 4.
    The color is given to strings in the order they located in sub tables, so they will be assigned by first, second, third and forth color consequentially.

    If there's a fifth string, it's ignored since there's no palette avaliable.
    If you only need 2 of these four colors, you can type the table like this
    { '<voxbox .... />', nil, '<voxbox .... />' }

    You can't use an empty string here since it's a string and mod would recognise that as data and feed it with color and add to vehicle data, which is very likely to cause a wave of errors.

  4. Now you need to open your .vox model file to help you understand this section

    The data string requires a special structure to make paint can be picked correctly. Therefore naming your vox model objects completely random helps nothing. Here's the name I given to my vox objects:


    you can clearly see there's a specific structure exists.
    This is how this structure looks like:
    nameIndex-Num
    where
    1. name is the name of this vox model object
    2. Index is the paintID of object, paintID is used as a parameter in function
    3. -
    4. Num is a integer number, starts from 1
    So how this thing works?

    Example: here's the object name and separated according to structure:
    doorRightPaint1-1 : doorRight , Paint1 , - , 1 doorRightPaint1-2 : doorRight , Paint1 , - , 2 doorLeftPaint1-1 : doorLeft , Paint1 , - , 1 doorLeftPaint1-2 : doorLeft , Paint1 , - , 2
    So this is how you should fill in string data and function parameter
    string: '<voxbox size="11 21 2" brush="MOD/voxModel.vox" object="doorRight"/>' function AddPaint() parameter 'paintID': "Paint1"

    You may think: How this heck gonna work?

    Use this as sample:
    { '<voxbox size="2 7 3" brush="MOD/voxModel.vox" object="doorRight"/>', '<voxbox size="2 14 19" brush="MOD/voxModel.vox" object="doorRight"/>' }, { '<voxbox size="4 3 1" brush="MOD/voxModel.vox" object="mirror"/>', '<voxbox size="2 7 3" brush="MOD/voxModel.vox" object="doorLeft"/>', '<voxbox size="2 14 19" brush="MOD/voxModel.vox" object="doorLeft"/>' }
    During painting process, the mod reads the object name, so for both objects here: doorRight. Then it automatically fills up the name.
    Index is picked up from function's "paintID" parameter, here it's ' Paint1 ', number is the position of string in sub table.
    This is the resultant object name (in order of table):
    doorRightPaint1-1 doorRightPaint1-2 mirrorPaint1-1 doorLeftPaint1-2 doorLeftPaint1-3

    That's the reason we have a special format for objects naming.

  5. It's painful to deal with anything massive, so I added a feature to make life easier.

    Since you always have a default paint (and I recommend that be single color), you can use this as background so you don't have to completely make a new paint.

    For example:

    This double-decker paint is like this in MagicaVoxel:

    So I only made those which uses other colors, all the rest uses default paint. This can massively reduce file size and difficulty of making new paints

    It's very simple to get this feature: Replacing the 1st string in sub table by "DEFAULT"
    { "DEFAULT", '<voxbox ..../>', '<voxbox ..../>' }
- - - - - - | - XMLdata
This is the most complex structure of parameter among all vehicle data.

This parameter have two types: string & table

String
In this case, this parameter is same as XMLstring, no additional configuration panel would show up.

Table
In this case, when this component is selected, an additional configuration panel is shown.

  1. Constant & Optional
    This represents no matter which optional part is selected, the constant component is always added to vehicle.
    Example:

    This roof rack have 3 optional lights, but even if none of these are selected, the roof rack is always assembled

    This is the basic format of this type of data:
    { {'<instance file="MOD/prefab01.xml"/>'}, {'<instance file="MOD/prefab2x2-6.xml"/>', name = "6 Single lights"}, {'<instance file="MOD/prefab14x2.xml"/>', name = "Light bar (14 vox)"}, {'<instance file="MOD/prefab16x2.xml"/>', name = "Light bar (16 vox)"} }

    The first sub table is constant component, all the rest (here's 3) are optional

  2. Optional Only
    This represents if no optional part is selected, nothing is added to vehicle.
    Example:

    6 optional rear bumpers, but if none of these are selected, nothing is assembled

    This is the basic format of this type of data:
    { {}, {'<instance file="MOD/prefab1a.xml"/>', name = "Type 1A"}, {'<instance file="MOD/prefab1b.xml"/>', name = "Type 1B"}, {'<instance file="MOD/prefab2a.xml"/>', name = "Type 2A"}, {'<instance file="MOD/prefab2b.xml"/>', name = "Type 2B"}, {'<instance file="MOD/prefab3a.xml"/>', name = "Type 3A"}, {'<instance file="MOD/prefab3b.xml"/>', name = "Type 3B"} }

    The first sub table is empty so there's no constant component, all the rest (here's 6) are optional

  3. Grouped Constant

    This parameter MUST be used with 'replace' parameter of AddComponent() function
    More about 'replace' would be covered in 'Keyworks & Replacing' section

    A special parameter is used to determine this: noOption
    { {noOption = true}, {'<vox file="MOD/vox/main.vox" object="mirrorLch"/>'}, {'<vox file="MOD/vox/main.vox" object="mirrorRch"/>'} }

    When this parameter is added, the optional panel would not show up. All parts in list will be treated as constant parts and added to their expected place.

  4. Additional Parameters
    1. Name (name)
      This parameter determines name of this component, otherwise it's an empty string. Only for optional parts, the constant part still uses it's own name.
      Example:
      { {'<....../>'}, -- constant {'<....../>', name = "Name of this component"} }

    2. Group (group)
      This parameter separate parts into groups, only one part can be picked in each group. Group id MUST be positive integer numbers. When not added, this part is not grouped and can co-exist with other parts. Only for optional parts.
      Example:
      { {'<....../>'}, -- constant {'<....../>', group = 1}, {'<....../>'}, {'<....../>', group = 1}, {'<....../>', group = 2}, {'<....../>', group = 2}, {'<....../>', group = 2}, {'<....../>'} }

    3. Paintable (canPaint)
      This parameter makes paintable (voxbox & light) parts use customized color. Optional colors are same as vehicle paint. An additional color selection panel is drawn. Only for optional parts.
      Example:
      { {'<....../>', canPaint = true}, -- constant {'<....../>'}, {'<....../>'} }
      Color selection panel:


    4. Instances (instance)
      This parameter marks ALL parts data string as instances, because instances need another logic of painting compared to voxbox & light. If you want to avoid interruptions, give ALL color parameters inside the instance that you don't want to paint a value. Only for optional parts.

      This parameter can be ignored when you're not using 'canPaint'.

      Example:
      { {'<....../>', canPaint = true, instance = true}, -- constant {'<....../>'}, {'<....../>'} }

    5. Fuzzy matching (approx)
      This parameter marks current component to use fuzzy matching when replacing.

      Example:
      { {'<....../>', approx = true}, -- constant {'<....../>'}, {'<....../>'} } it's replace target: "repA"
      So it ONLY search for "repA" target and ignore other additional suffix information, so "repA_2", "repAnother" are treated same as "repA", "comprepA" is not since it's a different target (or regard it as another prefix before "repA")
- - - - | - Keywords & Replacing (replace)
- - - - - - | - Keywords
Basic
There are 4 types of keywords used in this mod:
  • REPLACECHASSIS
  • REPLACEPAINT
  • REPLACEBODY
  • REPLACECOMP
You may already notice that each represents a category of parts. Yes, the last several characters represent the category.
  • REPLACECHASSIS -- Chassis
  • REPLACEPAINT -- Paint
  • REPLACEBODY -- Body
  • REPLACECOMP -- Component

All keywords MUST be add outside any xml prolog.
Example:
Good: <voxbox .... />\ REPLACEBODYby2aEND\ <vox ..../>\ <vox ..../>\ Bad: <voxbox tags="...." REPLACECOMPdr4END file="...." object="...."/>

Syntax

Since keywords are string, you can add it to anywhere which is part of vehicle xml data.
For example, you can add a REPLACEPAINT keyword into a body's data string, so this body is paintable.

  1. REPLACECHASSIS
    REPLACECHASSIS+number+END, number is id of string inside XMLlist parameter of AddChassis() function.
    REPLACECHASSIS01END REPLACECHASSIS27END
    You can imagine the 'REPLACECHASSISxx' and 'END' as a bracket so it can replace multiple lines of data. (hope you still remember the usage of ' \ ')
    REPLACECHASSIS04\ <voxbox ....../>\ <vox ....../>\ <joint ....../>\ END\

  2. REPLACEPAINT
    REPLACEPAINT+number, number is index of sub tables inside XMLtable parameter of AddPaint() function.
    REPLACEPAINT05 REPLACEPAINT24 REPLACEPAINT55

  3. REPLACEBODY
    REPLACEBODY+replace+END, replace is parameter 'replace' of AddBody() function.
    REPLACEBODYdoor1END REPLACEBODYtgts_4dEND
    You can imagine the 'REPLACEBODYxxx' and 'END' as a bracket so it can replace multiple lines of data. (hope you still remember the usage of ' \ ')
    REPLACEBODYbxA_4\ <voxbox ....../>\ <vox ....../>\ <joint ....../>\ END\

  4. REPLACECOMP
    REPLACECOMP+replace+END, replace is parameter 'replace' of AddComponent() function.
    REPLACECOMPdoor1END REPLACECOMPtgts_4dEND
    You can imagine the 'REPLACECOMPxxx' and 'END' as a bracket so it can replace multiple lines of data. (hope you still remember the usage of ' \ ')
    REPLACECOMPbxA_4\ <voxbox ....../>\ <vox ....../>\ <joint ....../>\ END\
- - - - - - | - Replacing (replace)
The ' replace ' parameter is used by AddBody() and AddComponent(), but the have same format and syntax.

This parameter is a string, to avoid interruptions, please only use letters, numbers and underline ' _ '

You can regard this as a label, so the mod would find where this label exists.
For example: you put 'body_A1' as parameter in AddBody(), so the mod would find the keyword REPLACEBODY with this label. if found, the content are replaced automatically, otherwise leave original vehicle data as it.

A slightly different for components is they can have tables, so an additional label is required.
Example:
This is the component's XMLdata & ' replace ' parameter string is ' compA1 '
{ {'<instance file="MOD/prefab01.xml"/>'}, {'<instance file="MOD/prefab02.xml"/>'}, {'<instance file="MOD/prefab03.xml"/>'}, {'<instance file="MOD/prefab04.xml"/>'} }

To ensure everything can be replaced correctly, you need to add a suffix to your ' replace ' string, where the suffix is a underline ' _ ' with index of sub table.
REPLACECOMPcompA1_1 REPLACECOMPcompA1_2 REPLACECOMPcompA1_3 REPLACECOMPcompA1_4
This label CAN NOT be added to 'replace' parameter
- - | - Additional Content
  1. Use ' \ ' at end of each line of string to act as 'enter', otherwise Lua would regard the string reached the end; or use '[[' and ']]' if you're tired of adding '\' (check Lua documentation for more information)
  2. Loading order of parts of vehicles during spawning is
    chassis (vehicle parameters & body offset) \/ cabin \/ chassis (xml data) \/ body \/ components \/ paint
Removing
It's easy to remove these from your vehicle pack

  1. Delete YLVF folder and YLVFdata.lua
  2. Open your spawn.txt, remove this line
    YLVF/YLVF.xml : YLVF/DUMMY
  3. Noew your vehicle pack is removed from list